176 changes: 158 additions & 18 deletions src/socket.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,11 @@ typedef int socklen_t;
typedef int socket_t;
#endif

#if USE_BLUETOOTH
#include <bluetooth/bluetooth.h>
#include <bluetooth/rfcomm.h>
#endif

#include "constants.h"
#include "debug.h"
#include "settings.h"
Expand All @@ -59,6 +64,7 @@ typedef int socket_t;
#include <iomanip>
#include "util/string.h"
#include "util/numeric.h"
#include "config.h"

// Set to true to enable verbose debug output
bool socket_enable_debug_output = false;
Expand Down Expand Up @@ -110,13 +116,22 @@ Address::Address(u8 a, u8 b, u8 c, u8 d, u16 port)
setPort(port);
}

Address::Address(const IPv6AddressBytes * ipv6_bytes, u16 port)
Address::Address(const IPv6AddressBytes *ipv6_bytes, u16 port)
{
memset(&m_address, 0, sizeof(m_address));
setAddress(ipv6_bytes);
setPort(port);
}

#if USE_BLUETOOTH
Address::Address(const BluetoothAddressBytes *bt_bytes, u16 port)
{
memset(&m_address, 0, sizeof(m_address));
setAddress(bt_bytes);
setPort(port);
}
#endif

// Equality (address family, address and port must be equal)
bool Address::operator==(Address &address)
{
Expand All @@ -132,6 +147,13 @@ bool Address::operator==(Address &address)
return memcmp(m_address.ipv6.sin6_addr.s6_addr,
address.m_address.ipv6.sin6_addr.s6_addr, 16) == 0;
}
#if USE_BLUETOOTH
else if(m_addr_family == AF_BLUETOOTH)
{
return memcmp(m_address.bluetooth.rc_bdaddr,
address.bluetooth.rc_bdaddr, 6) == 0;
}
#endif
else
return false;
}
Expand All @@ -143,6 +165,11 @@ bool Address::operator!=(Address &address)

void Address::Resolve(const char *name)
{
#if USE_BLUETOOTH
if(m_addr_family == AF_BLUETOOTH) {
throw ResolveError("Bluetooth does not support name resolving");
}
#endif
if (!name || name[0] == 0) {
if (m_addr_family == AF_INET) {
setAddress((u32) 0);
Expand Down Expand Up @@ -225,14 +252,34 @@ std::string Address::serializeString() const
}
return os.str();
}
#if USE_BLUETOOTH
else if(m_addr_family == AF_BLUETOOTH)
{
char dest[18];
ba2str(&m_address.bluetooth.rc_bdaddr, dest);
return std::string(dest);
}
#endif
else
return std::string("");
#else
char str[INET6_ADDRSTRLEN];
if (inet_ntop(m_addr_family, (m_addr_family == AF_INET) ? (void*)&(m_address.ipv4.sin_addr) : (void*)&(m_address.ipv6.sin6_addr), str, INET6_ADDRSTRLEN) == NULL) {
return std::string("");
if(m_addr_family == AF_INET || m_addr_family == AF_INET6) {
char str[INET6_ADDRSTRLEN];
if (inet_ntop(m_addr_family, (m_addr_family == AF_INET) ? (void*)&(m_address.ipv4.sin_addr) : (void*)&(m_address.ipv6.sin6_addr), str, INET6_ADDRSTRLEN) == NULL) {
return std::string("");
}
return std::string(str);
}
#if USE_BLUETOOTH
else if(m_addr_family == AF_BLUETOOTH)
{
char dest[18];
ba2str(&m_address.bluetooth.rc_bdaddr, dest);
return std::string(dest);
}
return std::string(str);
#endif
else
return std::string("");
#endif
}

Expand All @@ -246,6 +293,13 @@ struct sockaddr_in6 Address::getAddress6() const
return m_address.ipv6; // NOTE: NO PORT INCLUDED, use getPort()
}

#if USE_BLUETOOTH
struct sockaddr_rc Address::getAddressBt() const
{
return m_address.bluetooth;
}
#endif

u16 Address::getPort() const
{
return m_port;
Expand All @@ -270,6 +324,13 @@ bool Address::isZero() const
return memcmp(m_address.ipv6.sin6_addr.s6_addr,
zero, 16) == 0;
}
#if USE_BLUETOOTH
else if (m_addr_family == AF_BLUETOOTH) {
static const char zero[6] = {0};
return memcmp(m_address.bluetooth.rc_bdaddr,
zero, 6) == 0;
}
#endif
return false;
}

Expand All @@ -288,7 +349,7 @@ void Address::setAddress(u8 a, u8 b, u8 c, u8 d)
m_address.ipv4.sin_addr.s_addr = addr;
}

void Address::setAddress(const IPv6AddressBytes * ipv6_bytes)
void Address::setAddress(const IPv6AddressBytes *ipv6_bytes)
{
m_addr_family = AF_INET6;
m_address.ipv6.sin6_family = AF_INET6;
Expand All @@ -298,9 +359,29 @@ void Address::setAddress(const IPv6AddressBytes * ipv6_bytes)
memset(m_address.ipv6.sin6_addr.s6_addr, 0, 16);
}

#if USE_BLUETOOTH
void Address::setAddress(const BluetoothAddressBytes *bt_bytes)
{
m_addr_family = AF_BLUETOOTH;
m_address.bluetooth.rc_family = AF_BLUETOOTH;
m_address.bluetooth.rc_channel = 1;
if(bt_bytes)
memcpy(m_address.bluetooth.rc_bdaddr, bt_bytes->bytes, 6);
else
memset(m_address.bluetooth.rc_bdaddr, 0, 6);
}
#endif

void Address::setPort(u16 port)
{
m_port = port;
if(m_addr_family == AF_INET || m_addr_family == AF_INET6)
m_port = port;
#if USE_BLUETOOTH
else if(m_addr_family == AF_BLUETOOTH) {
m_port = port % 0xff;
m_address.bluetooth.rc_channel = port % 0xff;
}
#endif
}

void Address::print(std::ostream *s) const
Expand All @@ -309,30 +390,43 @@ void Address::print(std::ostream *s) const
{
(*s) << "[" << serializeString() << "]:" << m_port;
}
else
else if(m_addr_family == AF_INET)
{
(*s) << serializeString() << ":" << m_port;
}
#if USE_BLUETOOTH
else if(m_addr_family == AF_BLUETOOTH)
{
(*s) << "[" << serializeString() << "]:" << m_port;
}
#endif
}

/*
UDPSocket
*/

UDPSocket::UDPSocket(bool ipv6)
UDPSocket::UDPSocket(int addr_family)
{
if(g_sockets_initialized == false)
throw SocketException("Sockets not initialized");

// Use IPv6 if specified
m_addr_family = ipv6 ? AF_INET6 : AF_INET;
m_handle = socket(m_addr_family, SOCK_DGRAM, IPPROTO_UDP);
m_addr_family = addr_family;
if(m_addr_family == AF_INET || m_addr_family == AF_INET6)
m_handle = socket(m_addr_family, SOCK_DGRAM, IPPROTO_UDP);
#if USE_BLUETOOTH
else if(m_addr_family == AF_BLUETOOTH)
m_handle = socket(m_addr_family, SOCK_STREAM, BTPROTO_RFCOMM);
#endif
else
throw SocketException("Unknown address family");

if(socket_enable_debug_output)
{
dstream << "UDPSocket(" << (int) m_handle
<< ")::UDPSocket(): ipv6 = "
<< (ipv6 ? "true" : "false")
<< ")::UDPSocket(): addr_family = "
<< m_addr_family
<< std::endl;
}

Expand All @@ -342,6 +436,9 @@ UDPSocket::UDPSocket(bool ipv6)
}

setTimeoutMs(0);
#if USE_BLUETOOTH
bt_init_done = false;
#endif
}

UDPSocket::~UDPSocket()
Expand All @@ -363,9 +460,9 @@ void UDPSocket::Bind(Address addr)
{
if(socket_enable_debug_output)
{
dstream << "UDPSocket(" << (int) m_handle << ")::Bind(): "
<< addr.serializeString() << ":"
<< addr.getPort() << std::endl;
dstream << "UDPSocket(" << (int) m_handle << ")::Bind(): ";
addr.print(dstream);
dstream << std::endl;
}

if (addr.getFamily() != m_addr_family)
Expand All @@ -392,7 +489,7 @@ void UDPSocket::Bind(Address addr)
throw SocketException("Failed to bind socket");
}
}
else
else if(m_addr_family == AF_INET)
{
struct sockaddr_in address;
memset(&address, 0, sizeof(address));
Expand All @@ -409,10 +506,39 @@ void UDPSocket::Bind(Address addr)
throw SocketException("Failed to bind socket");
}
}
#if USE_BLUETOOTH
else if(m_addr_family == AF_BLUETOOTH)
{
btaddr = addr.getAddressBt();
// We do not do anything here yet
// because we do not yet know whether this is
// a server socket or client socket
}
#endif
else
throw SocketException("Unknown address family");
}

#if USE_BLUETOOTH
void UDPSocket::bt_do_clientinit()
{
// This method is called if the Send or Recv method is called first
if(connect(m_handle, (const struct sockaddr *) &btaddr, sizeof(btaddr)) < 0) {
dstream << (int) m_handle << ": Connect failed: "
<< strerror(errno) << std::endl;
throw SocketException("Failed to bind socket");
}
bt_init_done = true;
}
#endif

void UDPSocket::Send(const Address & destination, const void * data, int size)
{
#if USE_BLUETOOTH
if(m_addr_family == AF_BLUETOOTH && !bt_init_done)
bt_do_clientinit();
#endif

bool dumping_packet = false; // for INTERNET_SIMULATOR

if(INTERNET_SIMULATOR)
Expand Down Expand Up @@ -465,7 +591,7 @@ void UDPSocket::Send(const Address & destination, const void * data, int size)
sent = sendto(m_handle, (const char *) data, size,
0, (struct sockaddr *) &address, sizeof(struct sockaddr_in6));
}
else
else if(m_addr_family == AF_INET6)
{
struct sockaddr_in address = destination.getAddress();
address.sin_port = htons(destination.getPort());
Expand All @@ -481,6 +607,10 @@ void UDPSocket::Send(const Address & destination, const void * data, int size)

int UDPSocket::Receive(Address & sender, void * data, int size)
{
#if USE_BLUETOOTH
if(m_addr_family == AF_BLUETOOTH && !bt_init_done)
bt_do_clientinit();
#endif
// Return on timeout
if(WaitData(m_timeout_ms) == false)
{
Expand Down Expand Up @@ -562,6 +692,16 @@ void UDPSocket::setTimeoutMs(int timeout_ms)

bool UDPSocket::WaitData(int timeout_ms)
{
#if USE_BLUETOOTH
if(m_addr_family == AF_BLUETOOTH && !bt_init_done) {
// Server socket
// Bind it to the address and put it into listen mode
bind(m_handle, (const struct sockaddr *) &btaddr, sizeof(btaddr));
listen(m_handle, 1);
// TODO: need to make a seperate thread to listen to the socket, accept connections
// TODO: then need to make this functions select() all sockets
}
#endif
fd_set readset;
int result;

Expand Down
52 changes: 42 additions & 10 deletions src/socket.h
Original file line number Diff line number Diff line change
Expand Up @@ -35,10 +35,16 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include <netinet/in.h>
#endif

#if USE_BLUETOOTH
#include <bluetooth/bluetooth.h>
#include <bluetooth/rfcomm.h>
#endif

#include <ostream>
#include <string.h>
#include "irrlichttypes.h"
#include "exceptions.h"
#include "config.h"

extern bool socket_enable_debug_output;

Expand Down Expand Up @@ -79,35 +85,56 @@ class IPv6AddressBytes
IPv6AddressBytes() { memset(bytes, 0, 16); }
};

#if USE_BLUETOOTH
class BluetoothAddressBytes
{
public:
u8 bytes[6];
BluetoothAddressBytes() { memset(bytes, 0, 6); }
};
#endif

class Address
{
public:
Address();
Address(u32 address, u16 port);
Address(u8 a, u8 b, u8 c, u8 d, u16 port);
Address(const IPv6AddressBytes * ipv6_bytes, u16 port);
bool operator==(Address &address);
bool operator!=(Address &address);
// Resolve() may throw ResolveError (address is unchanged in this case)
void Resolve(const char *name);
struct sockaddr_in getAddress() const;
void setPort(unsigned short port);

unsigned short getPort() const;
void setAddress(u32 address);
void setAddress(u8 a, u8 b, u8 c, u8 d);
void setAddress(const IPv6AddressBytes * ipv6_bytes);
struct sockaddr_in6 getAddress6() const;
int getFamily() const;
bool isIPv6() const;
bool isZero() const;
void setPort(unsigned short port);
void print(std::ostream *s) const;
std::string serializeString() const;
// IPv4 stuff
Address(u32 address, u16 port);
Address(u8 a, u8 b, u8 c, u8 d, u16 port);
struct sockaddr_in getAddress() const;
void setAddress(u32 address);
void setAddress(u8 a, u8 b, u8 c, u8 d);
// IPv6 stuff
Address(const IPv6AddressBytes *ipv6_bytes, u16 port);
void setAddress(const IPv6AddressBytes *ipv6_bytes);
struct sockaddr_in6 getAddress6() const;
bool isIPv6() const;
// Bluetooth stuff
#if USE_BLUETOOTH
Address(const BluetoothAddressBytes *bt_bytes, u16 port);
void setAddress(const BluetoothAddressBytes *bt_bytes);
struct sockaddr_rc getAddressBt() const;
#endif
private:
unsigned int m_addr_family;
union
{
struct sockaddr_in ipv4;
struct sockaddr_in6 ipv6;
#if USE_BLUETOOTH
struct sockaddr_rc bluetooth;
#endif
} m_address;
u16 m_port; // Port is separate from sockaddr structures
};
Expand All @@ -131,6 +158,11 @@ class UDPSocket
int m_handle;
int m_timeout_ms;
int m_addr_family;
#if USE_BLUETOOTH
struct sockaddr_rc btaddr;
bool bt_init_done;
void bt_do_clientinit();
#endif
};

#endif
Expand Down