|
|
@ -15,30 +15,40 @@
|
|
|
|
#include "packet.h"
|
|
|
|
#include "packet.h"
|
|
|
|
#include "udp.h"
|
|
|
|
#include "udp.h"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
|
|
* Create an UDP socket but don't listen yet.
|
|
|
|
|
|
|
|
* @param bind the addresses to bind to.
|
|
|
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
NetworkUDPSocketHandler::NetworkUDPSocketHandler(NetworkAddressList *bind)
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
if (bind != NULL) {
|
|
|
|
|
|
|
|
for (NetworkAddress *addr = bind->Begin(); addr != bind->End(); addr++) {
|
|
|
|
|
|
|
|
*this->bind.Append() = *addr;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
|
|
|
*this->bind.Append() = NetworkAddress(NULL, 0, AF_INET);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
/**
|
|
|
|
* Start listening on the given host and port.
|
|
|
|
* Start listening on the given host and port.
|
|
|
|
* @param address the host to listen on
|
|
|
|
* @return true if at least one port is listening
|
|
|
|
* @param broadcast whether to allow broadcast sending/receiving
|
|
|
|
|
|
|
|
* @return true if the listening succeeded
|
|
|
|
|
|
|
|
*/
|
|
|
|
*/
|
|
|
|
bool NetworkUDPSocketHandler::Listen(NetworkAddress address, bool broadcast)
|
|
|
|
bool NetworkUDPSocketHandler::Listen()
|
|
|
|
{
|
|
|
|
{
|
|
|
|
/* Make sure socket is closed */
|
|
|
|
/* Make sure socket is closed */
|
|
|
|
this->Close();
|
|
|
|
this->Close();
|
|
|
|
|
|
|
|
|
|
|
|
this->sock = address.Listen(AF_INET, SOCK_DGRAM);
|
|
|
|
for (NetworkAddress *addr = this->bind.Begin(); addr != this->bind.End(); addr++) {
|
|
|
|
|
|
|
|
addr->Listen(AF_UNSPEC, SOCK_DGRAM, &this->sockets);
|
|
|
|
if (broadcast) {
|
|
|
|
|
|
|
|
/* Enable broadcast */
|
|
|
|
|
|
|
|
unsigned long val = 1;
|
|
|
|
|
|
|
|
#ifndef BEOS_NET_SERVER /* will work around this, some day; maybe. */
|
|
|
|
|
|
|
|
setsockopt(this->sock, SOL_SOCKET, SO_BROADCAST, (char *) &val, sizeof(val));
|
|
|
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
DEBUG(net, 1, "[udp] listening on port %s", address.GetAddressAsString());
|
|
|
|
for (SocketList::iterator s = this->sockets.Begin(); s != this->sockets.End(); s++) {
|
|
|
|
|
|
|
|
DEBUG(net, 1, "[udp] listening on port %s", s->first.GetAddressAsString());
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
return this->sockets.Length() != 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
/**
|
|
|
@ -46,10 +56,10 @@ bool NetworkUDPSocketHandler::Listen(NetworkAddress address, bool broadcast)
|
|
|
|
*/
|
|
|
|
*/
|
|
|
|
void NetworkUDPSocketHandler::Close()
|
|
|
|
void NetworkUDPSocketHandler::Close()
|
|
|
|
{
|
|
|
|
{
|
|
|
|
if (!this->IsConnected()) return;
|
|
|
|
for (SocketList::iterator s = this->sockets.Begin(); s != this->sockets.End(); s++) {
|
|
|
|
|
|
|
|
closesocket(s->second);
|
|
|
|
closesocket(this->sock);
|
|
|
|
}
|
|
|
|
this->sock = INVALID_SOCKET;
|
|
|
|
this->sockets.Clear();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
NetworkRecvStatus NetworkUDPSocketHandler::CloseConnection()
|
|
|
|
NetworkRecvStatus NetworkUDPSocketHandler::CloseConnection()
|
|
|
@ -62,18 +72,35 @@ NetworkRecvStatus NetworkUDPSocketHandler::CloseConnection()
|
|
|
|
* Send a packet over UDP
|
|
|
|
* Send a packet over UDP
|
|
|
|
* @param p the packet to send
|
|
|
|
* @param p the packet to send
|
|
|
|
* @param recv the receiver (target) of the packet
|
|
|
|
* @param recv the receiver (target) of the packet
|
|
|
|
|
|
|
|
* @param all send the packet using all sockets that can send it
|
|
|
|
|
|
|
|
* @param broadcast whether to send a broadcast message
|
|
|
|
*/
|
|
|
|
*/
|
|
|
|
void NetworkUDPSocketHandler::SendPacket(Packet *p, NetworkAddress *recv)
|
|
|
|
void NetworkUDPSocketHandler::SendPacket(Packet *p, NetworkAddress *recv, bool all, bool broadcast)
|
|
|
|
{
|
|
|
|
{
|
|
|
|
int res;
|
|
|
|
if (this->sockets.Length() == 0) this->Listen();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
for (SocketList::iterator s = this->sockets.Begin(); s != this->sockets.End(); s++) {
|
|
|
|
|
|
|
|
/* Not the same type */
|
|
|
|
|
|
|
|
if (s->first.GetAddress()->ss_family != recv->GetAddress()->ss_family) continue;
|
|
|
|
|
|
|
|
|
|
|
|
p->PrepareToSend();
|
|
|
|
p->PrepareToSend();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#ifndef BEOS_NET_SERVER /* will work around this, some day; maybe. */
|
|
|
|
|
|
|
|
if (broadcast) {
|
|
|
|
|
|
|
|
/* Enable broadcast */
|
|
|
|
|
|
|
|
unsigned long val = 1;
|
|
|
|
|
|
|
|
setsockopt(s->second, SOL_SOCKET, SO_BROADCAST, (char *) &val, sizeof(val));
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
|
|
/* Send the buffer */
|
|
|
|
/* Send the buffer */
|
|
|
|
res = sendto(this->sock, (const char*)p->buffer, p->size, 0, (struct sockaddr *)recv->GetAddress(), recv->GetAddressLength());
|
|
|
|
int res = sendto(s->second, (const char*)p->buffer, p->size, 0, (struct sockaddr *)recv->GetAddress(), recv->GetAddressLength());
|
|
|
|
|
|
|
|
|
|
|
|
/* Check for any errors, but ignore it otherwise */
|
|
|
|
/* Check for any errors, but ignore it otherwise */
|
|
|
|
if (res == -1) DEBUG(net, 1, "[udp] sendto failed with: %i", GET_LAST_ERROR());
|
|
|
|
if (res == -1) DEBUG(net, 1, "[udp] sendto(%s) failed with: %i", recv->GetAddressAsString(), GET_LAST_ERROR());
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (!all) break;
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
/**
|
|
|
@ -81,22 +108,17 @@ void NetworkUDPSocketHandler::SendPacket(Packet *p, NetworkAddress *recv)
|
|
|
|
*/
|
|
|
|
*/
|
|
|
|
void NetworkUDPSocketHandler::ReceivePackets()
|
|
|
|
void NetworkUDPSocketHandler::ReceivePackets()
|
|
|
|
{
|
|
|
|
{
|
|
|
|
|
|
|
|
for (SocketList::iterator s = this->sockets.Begin(); s != this->sockets.End(); s++) {
|
|
|
|
struct sockaddr_storage client_addr;
|
|
|
|
struct sockaddr_storage client_addr;
|
|
|
|
memset(&client_addr, 0, sizeof(client_addr));
|
|
|
|
memset(&client_addr, 0, sizeof(client_addr));
|
|
|
|
|
|
|
|
|
|
|
|
socklen_t client_len;
|
|
|
|
|
|
|
|
int nbytes;
|
|
|
|
|
|
|
|
Packet p(this);
|
|
|
|
Packet p(this);
|
|
|
|
int packet_len;
|
|
|
|
int packet_len = sizeof(p.buffer);
|
|
|
|
|
|
|
|
socklen_t client_len = sizeof(client_addr);
|
|
|
|
if (!this->IsConnected()) return;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
packet_len = sizeof(p.buffer);
|
|
|
|
|
|
|
|
client_len = sizeof(client_addr);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* Try to receive anything */
|
|
|
|
/* Try to receive anything */
|
|
|
|
SetNonBlocking(this->sock); // Some OSes seem to lose the non-blocking status of the socket
|
|
|
|
SetNonBlocking(s->second); // Some OSes seem to lose the non-blocking status of the socket
|
|
|
|
nbytes = recvfrom(this->sock, (char*)p.buffer, packet_len, 0, (struct sockaddr *)&client_addr, &client_len);
|
|
|
|
int nbytes = recvfrom(s->second, (char*)p.buffer, packet_len, 0, (struct sockaddr *)&client_addr, &client_len);
|
|
|
|
|
|
|
|
|
|
|
|
/* We got some bytes for the base header of the packet. */
|
|
|
|
/* We got some bytes for the base header of the packet. */
|
|
|
|
if (nbytes > 2) {
|
|
|
|
if (nbytes > 2) {
|
|
|
@ -113,6 +135,7 @@ void NetworkUDPSocketHandler::ReceivePackets()
|
|
|
|
/* Handle the packet */
|
|
|
|
/* Handle the packet */
|
|
|
|
this->HandleUDPPacket(&p, &address);
|
|
|
|
this->HandleUDPPacket(&p, &address);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|