FreeNOS
UDP.cpp
Go to the documentation of this file.
1 /*
2  * Copyright (C) 2015 Niek Linnenbank
3  *
4  * This program is free software: you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation, either version 3 of the License, or
7  * (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program. If not, see <http://www.gnu.org/licenses/>.
16  */
17 
18 #include <ByteOrder.h>
19 #include "NetworkServer.h"
20 #include "NetworkDevice.h"
21 #include "UDP.h"
22 #include "UDPSocket.h"
23 #include "UDPFactory.h"
24 
26  NetworkDevice &device,
27  NetworkProtocol &parent)
28  : NetworkProtocol(server, device, parent)
29 {
30 }
31 
33 {
34 }
35 
37 {
38  DEBUG("");
39 
41  m_server.registerDirectory(this, "/udp");
42  m_server.registerFile(m_factory, "/udp/factory");
43 
44  return FileSystem::Success;
45 }
46 
48  const ProcessID pid)
49 {
50  Size pos = 0;
51 
52  DEBUG("");
53 
54  UDPSocket *sock = new UDPSocket(m_server.getNextInode(), this, pid);
55  if (!sock)
56  {
57  ERROR("failed to allocate UDP socket");
58  return ZERO;
59  }
60 
61  if (!m_sockets.insert(pos, sock))
62  {
63  ERROR("failed to insert UDP socket");
64  delete sock;
65  return ZERO;
66  }
67  String filepath;
68  filepath << "/udp/" << pos;
69 
70  path << m_server.getMountPath() << filepath;
71  const FileSystem::Result result = m_server.registerFile(sock, *filepath);
72  if (result != FileSystem::Success)
73  {
74  ERROR("failed to register UDP socket: result = " << (int) result);
75  delete sock;
76  m_sockets.remove(pos);
77  }
78 
79  return sock;
80 }
81 
83 {
84  DEBUG("pid = " << pid);
85 
87  {
88  UDPSocket *sock = it.current();
89  if (sock->getProcessID() == pid)
90  {
91  it.remove();
92  }
93  else
94  {
95  it++;
96  }
97  }
98 
99  for (Size i = 0; i < MaxUdpSockets; i++)
100  {
101  UDPSocket *sock = m_sockets[i];
102  if (sock != ZERO && sock->getProcessID() == pid)
103  {
104  m_sockets.remove(i);
105  String path;
106  path << "/udp/" << i;
107  const FileSystem::Result result = m_server.unregisterFile(*path);
108  if (result != FileSystem::Success)
109  {
110  ERROR("failed to unregister UDPSocket at " << *path <<
111  " for PID " << pid << ": result = " << (int) result);
112  }
113  }
114  }
115 }
116 
118  const Size offset)
119 {
120  const Header *hdr = (const Header *)(pkt->data + sizeof(Ethernet::Header) + sizeof(IPV4::Header));
121  const u16 port = be16_to_cpu(hdr->destPort);
122 
123  DEBUG("port = " << port);
124 
125  // Process the packet if we have a socket on that port
126  UDPSocket **sock = (UDPSocket **) m_ports.get(port);
127  if (!sock)
128  {
129  DEBUG("dropped");
130  return FileSystem::NotFound;
131  }
132 
133  (*sock)->process(pkt);
134  return FileSystem::Success;
135 }
136 
138  const NetworkClient::SocketInfo *dest,
139  IOBuffer & buffer,
140  const Size size,
141  const Size offset)
142 {
144  Header *hdr;
145 
146  DEBUG("address = " << *IPV4::toString(dest->address) <<
147  " port = " << dest->port << " size = " << size);
148 
149  // Get a fresh packet
150  const FileSystem::Result result = m_parent.getTransmitPacket(&pkt, &dest->address, sizeof(dest->address),
151  NetworkProtocol::UDP, sizeof(Header) + size);
152  if (result != FileSystem::Success)
153  {
154  if (result != FileSystem::RetryAgain)
155  {
156  ERROR("failed to get transmit packet: result = " << (int) result);
157  }
158  return result;
159  }
160 
161  // Fill UDP header
162  hdr = (Header *) (pkt->data + pkt->size);
163  writeBe16(&hdr->sourcePort, src->port);
164  writeBe16(&hdr->destPort, dest->port);
165  writeBe16(&hdr->length, size + sizeof(Header));
166  writeBe16(&hdr->checksum, 0);
167 
168  // Insert payload. The payload is read from the given offset in the IOBuffer.
169  // Note that the payload must not overwrite past the packet buffer
170  const Size maximum = getMaximumPacketSize();
171  const Size needed = pkt->size + size;
172 
173  buffer.read(pkt->data + pkt->size + sizeof(Header),
174  needed > maximum ? maximum : needed, offset);
175 
176  // Calculate final checksum
177  write16(&hdr->checksum, checksum((IPV4::Header *)(pkt->data + pkt->size - sizeof(IPV4::Header)),
178  hdr, size));
179  DEBUG("checksum = " << (uint) hdr->checksum);
180 
181  // Increment packet size
182  pkt->size += sizeof(Header) + size;
183 
184  // Transmit now
185  return m_device.transmit(pkt);
186 }
187 
189  const u16 port)
190 {
191  DEBUG("port = " << port);
192 
193  if (!port)
194  {
196  }
197 
198  m_ports.insert(port, sock);
199  return FileSystem::Success;
200 }
201 
202 const ulong UDP::calculateSum(const u16 *ptr,
203  const Size bytes)
204 {
205  ulong sum = 0;
206  Size remain = bytes;
207 
208  for (;remain > 0; remain -= sizeof(u16), ptr++)
209  {
210  if (remain == sizeof(u8))
211  {
212  sum += read8(ptr);
213  break;
214  }
215  else
216  {
217  sum += read16(ptr);
218  }
219  }
220 
221  return sum;
222 }
223 
225  const UDP::Header *udp,
226  const Size datalen)
227 {
228  IPV4::PseudoHeader phr;
229  ulong sum = 0;
230 
231  // Setup a pseudo header
232  phr.reserved = 0;
233  phr.protocol = IPV4::UDP;
234  phr.source = read32(&ip->source);
235  phr.destination = read32(&ip->destination);
236  writeBe16(&phr.length, sizeof(Header) + datalen);
237  DEBUG("ip src = " << *IPV4::toString(phr.source) <<
238  " dst = " << *IPV4::toString(phr.destination));
239 
240  // Sum the pseudo header
241  sum += calculateSum((u16 *) &phr, sizeof(phr));
242  sum += calculateSum((u16 *) udp, sizeof(*udp) + datalen);
243 
244  // Keep only last 16 bits and add carry bits
245  sum = (sum >> 16) + (sum & 0xffff);
246  sum += (sum >> 16);
247 
248  // Take one's complement
249  sum = ~sum;
250  return (u16) sum;
251 }
IPV4::PseudoHeader::reserved
u8 reserved
Definition: IPV4.h:91
UDP::m_ports
HashTable< u16, UDPSocket * > m_ports
Maps UDP ports to UDP sockets.
Definition: UDP.h:169
UDP::~UDP
virtual ~UDP()
Destructor.
Definition: UDP.cpp:32
read32
const u32 read32(const void *data)
Read 32-bit integer (no conversion)
Definition: ByteOrder.h:242
NetworkProtocol
Network protocol abstraction class.
Definition: NetworkProtocol.h:39
UDP::Header
struct UDP::Header Header
Packet header format.
ulong
unsigned long ulong
Unsigned long number.
Definition: Types.h:47
UDP::sendPacket
FileSystem::Result sendPacket(const NetworkClient::SocketInfo *src, const NetworkClient::SocketInfo *dest, IOBuffer &buffer, const Size size, const Size offset)
Send packet.
Definition: UDP.cpp:137
FileSystemServer::getNextInode
u32 getNextInode()
Get next unused inode.
Definition: FileSystemServer.cpp:66
UDPFactory
User Datagram Protocol (UDP).
Definition: UDPFactory.h:38
writeBe16
void writeBe16(void *data, const u16 input)
Write 16-bit big endian integer.
Definition: ByteOrder.h:471
UDP.h
NetworkClient::SocketInfo::address
IPV4::Address address
Definition: NetworkClient.h:67
UDP::calculateSum
static const ulong calculateSum(const u16 *ptr, const Size bytes)
Calculate sum of artibrary data.
Definition: UDP.cpp:202
String
Abstraction of strings.
Definition: String.h:41
NetworkDevice
Network Device abstract class.
Definition: NetworkDevice.h:41
HashIterator
Iterate through a HashTable.
Definition: HashIterator.h:39
UDP::m_sockets
Index< UDPSocket, MaxUdpSockets > m_sockets
Contains all UDP sockets.
Definition: UDP.h:166
NetworkProtocol::m_parent
NetworkProtocol & m_parent
Parent upper-layer protocol instance.
Definition: NetworkProtocol.h:126
IPV4::Header::source
Address source
Definition: IPV4.h:76
FileSystem::InvalidArgument
@ InvalidArgument
Definition: FileSystem.h:55
ProcessID
u32 ProcessID
Process Identification Number.
Definition: Types.h:140
FileSystemServer::unregisterFile
FileSystem::Result unregisterFile(const char *path)
Remove a File from the FileSystemServer.
Definition: FileSystemServer.cpp:175
NetworkQueue::Packet::data
u8 * data
Definition: NetworkQueue.h:53
NetworkProtocol::UDP
@ UDP
Definition: NetworkProtocol.h:52
UDP::createSocket
UDPSocket * createSocket(String &path, const ProcessID pid)
Creates an UDP socket.
Definition: UDP.cpp:47
IPV4::Header
struct IPV4::Header Header
IP network packet header.
NetworkQueue::Packet::size
Size size
Definition: NetworkQueue.h:52
IPV4::PseudoHeader::destination
Address destination
Definition: IPV4.h:90
FileSystem::Success
@ Success
Definition: FileSystem.h:54
NetworkClient::SocketInfo::port
u16 port
Definition: NetworkClient.h:68
uint
unsigned int uint
Unsigned integer number.
Definition: Types.h:44
NetworkProtocol::m_device
NetworkDevice & m_device
Network device instance.
Definition: NetworkProtocol.h:123
NetworkSocket::getProcessID
ProcessID getProcessID() const
Get owner ProcessID.
Definition: NetworkSocket.cpp:36
UDP::process
virtual FileSystem::Result process(const NetworkQueue::Packet *pkt, const Size offset)
Process incoming network packet.
Definition: UDP.cpp:117
write16
void write16(void *data, const u16 input)
Write 16-bit integer (no conversion)
Definition: ByteOrder.h:305
DEBUG
#define DEBUG(msg)
Output a debug message to standard output.
Definition: Log.h:89
IPV4::PseudoHeader
Pseudo Header.
Definition: IPV4.h:87
NetworkDevice.h
NetworkServer
Networking server.
Definition: NetworkServer.h:40
UDPFactory.h
NetworkProtocol::getMaximumPacketSize
virtual const Size getMaximumPacketSize() const
Get maximum packet size.
Definition: NetworkProtocol.cpp:36
UDP::unregisterSockets
void unregisterSockets(const ProcessID pid)
Remove sockets for a process.
Definition: UDP.cpp:82
IPV4::PseudoHeader::length
u16 length
Definition: IPV4.h:93
HashTable::get
virtual const V * get(const K &key) const
Returns the first value for the given key.
Definition: HashTable.h:287
IPV4::PseudoHeader::protocol
u8 protocol
Definition: IPV4.h:92
u16
unsigned short u16
Unsigned 16-bit number.
Definition: Types.h:56
UDP::Header
Packet header format.
Definition: UDP.h:52
IOBuffer
Abstract Input/Output buffer.
Definition: IOBuffer.h:37
UDP::Header::destPort
u16 destPort
Definition: UDP.h:55
ByteOrder.h
UDP::Header::sourcePort
u16 sourcePort
Definition: UDP.h:54
Size
unsigned int Size
Any sane size indicator cannot go negative.
Definition: Types.h:128
UDP::bind
FileSystem::Result bind(UDPSocket *sock, const u16 port)
Bind to UDP port.
Definition: UDP.cpp:188
UDP::Header::checksum
u16 checksum
Definition: UDP.h:57
Ethernet::Header
Ethernet network packet header.
Definition: Ethernet.h:64
UDP::m_factory
UDPFactory * m_factory
Factory for creating new UDP sockets.
Definition: UDP.h:163
FileSystemServer::registerDirectory
FileSystem::Result registerDirectory(Directory *dir, const char *path)
Register a new Directory.
Definition: FileSystemServer.cpp:138
read16
const u16 read16(const void *data)
Read 16-bit integer (no conversion)
Definition: ByteOrder.h:256
IPV4::Header
IP network packet header.
Definition: IPV4.h:66
NetworkProtocol::getTransmitPacket
virtual FileSystem::Result getTransmitPacket(NetworkQueue::Packet **pkt, const void *address, const Size addressSize, const Identifier protocol, const Size payloadSize)
Get a new packet for transmission.
Definition: NetworkProtocol.cpp:41
IPV4::toString
static const String toString(const Address address)
Convert address to string.
Definition: IPV4.cpp:82
FileSystemServer::getMountPath
const char * getMountPath() const
Get mount path.
Definition: FileSystemServer.cpp:61
NetworkProtocol::m_server
NetworkServer & m_server
Network server instance.
Definition: NetworkProtocol.h:120
ERROR
#define ERROR(msg)
Output an error message.
Definition: Log.h:61
NetworkClient::SocketInfo
Socket information.
Definition: NetworkClient.h:65
FileSystem::Result
Result
Result code for filesystem Actions.
Definition: FileSystem.h:52
u8
unsigned char u8
Unsigned 8-bit number.
Definition: Types.h:59
NetworkDevice::transmit
virtual FileSystem::Result transmit(NetworkQueue::Packet *packet)=0
Add a network packet to the transmit queue.
FileSystem::RetryAgain
@ RetryAgain
Definition: FileSystem.h:57
NetworkServer.h
IPV4::PseudoHeader::source
Address source
Definition: IPV4.h:89
Index::remove
virtual bool remove(const Size position)
Removes the item at the given position.
Definition: Index.h:143
IPV4::Header::destination
Address destination
Definition: IPV4.h:77
UDP::MaxUdpSockets
static const Size MaxUdpSockets
Definition: UDP.h:45
FileSystem::NotFound
@ NotFound
Definition: FileSystem.h:56
IOBuffer::read
FileSystem::Result read(void *buffer, const Size size, const Size offset=ZERO)
Read bytes from the I/O buffer.
Definition: IOBuffer.cpp:156
HashIterator::hasCurrent
virtual bool hasCurrent() const
Check if there is a current item.
Definition: HashIterator.h:83
UDP::checksum
static const u16 checksum(const IPV4::Header *ip, const Header *header, const Size datalen)
Calculate ICMP checksum.
Definition: UDP.cpp:224
NetworkQueue::Packet
Represents a network packet.
Definition: NetworkQueue.h:50
IPV4::UDP
@ UDP
Definition: IPV4.h:56
Index::insert
virtual bool insert(Size &position, T *item)
Adds the given item, if possible.
Definition: Index.h:60
UDP::Header::length
u16 length
Definition: UDP.h:56
UDPSocket.h
ZERO
#define ZERO
Zero value.
Definition: Macros.h:43
UDP::initialize
virtual FileSystem::Result initialize()
Perform initialization.
Definition: UDP.cpp:36
UDPSocket
User Datagram Protocol (UDP) socket.
Definition: UDPSocket.h:42
HashTable::insert
virtual bool insert(const K &key, const V &value)
Inserts the given item to the HashTable.
Definition: HashTable.h:133
read8
const u8 read8(const void *data)
Read 8-bit integer.
Definition: ByteOrder.h:270
be16_to_cpu
#define be16_to_cpu(x)
Big endian 16-bit to CPU byte order.
Definition: ByteOrder.h:207
FileSystemServer::registerFile
FileSystem::Result registerFile(File *file, const char *path)
Register a new File.
Definition: FileSystemServer.cpp:115