1 /**
2  * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
3  * SPDX-License-Identifier: Apache-2.0.
4  */
5 
6 #pragma once
7 
8 #include <aws/core/Core_EXPORTS.h>
9 #include <aws/core/utils/memory/stl/AWSString.h>
10 #include <cstdint>
11 struct sockaddr;
12 
13 namespace Aws
14 {
15     namespace Net
16     {
17         // 8K is aligned with default monitoring packet size.
18         const static size_t UDP_BUFFER_SIZE = 8192;
19         /**
20          * SimpleUDP definition.
21          */
22         class AWS_CORE_API SimpleUDP
23         {
24         public:
25             /**
26              * @brief Constructor of SimpleUDP
27              * @param addressFamily, AF_INET for IPV4 or AF_INET6 for IPV6
28              * @param sendBufSize, if nonzero, try set socket's send buffer size to this value.
29              * @param receieveBufSize, if nonzero, try set socket's receive buffer size to this value.
30              * @param nonBlocking, if it is true, implementation will try to create a non-blocking underlying UDP socket.
31              * Implementation should create and set the underlying udp socket.
32              */
33             SimpleUDP(int addressFamily, size_t sendBufSize = UDP_BUFFER_SIZE, size_t receiveBufSize = UDP_BUFFER_SIZE, bool nonBlocking = true);
34 
35             /**
36             * @brief An easy constructor of an IPV4 or IPV6 SimpleUDP
37             * @param addressFamily, either AF_INET for IPV4 or AF_INET6 for IPV6
38             * @param sendBufSize, if nonzero, try set socket's send buffer size to this value.
39             * @param receieveBufSize, if nonzero, try set socket's receive buffer size to this value.
40             * @param nonBlocking, if it is true, implementation will try to create a non-blocking underlying UDP socket.
41             * Implementation should create and set the underlying udp socket.
42             */
43             SimpleUDP(bool IPV4 = true, size_t sendBufSize = UDP_BUFFER_SIZE, size_t receiveBufSize = UDP_BUFFER_SIZE, bool nonBlocking = true);
44 
45             /**
46             * @brief An easy constructor of SimpleUDP based on host and port
47             * @param host, the host that packets will be sent to, could be ipv4 or ipv6 address, or a hostname
48             * Note that "localhost" is not necessarily bind to 127.0.0.1, it could bind to ipv6 address ::1, or other type of ip addresses. If you pass localhost here, we will go through getaddrinfo procedure on Linux and Windows.
49             * @param port, the port number that the host listens on.
50             * @param sendBufSize, if nonzero, try set socket's send buffer size to this value.
51             * @param receieveBufSize, if nonzero, try set socket's receive buffer size to this value.
52             * @param nonBlocking, if it is true, implementation will try to create a non-blocking underlying UDP socket.
53             * Implementation should create and set the underlying udp socket.
54             */
55             SimpleUDP(const char* host, unsigned short port, size_t sendBufSize = UDP_BUFFER_SIZE, size_t receiveBufSize = UDP_BUFFER_SIZE, bool nonBlocking = true);
56 
57             ~SimpleUDP();
58 
59             /**
60              * @brief Connect underlying udp socket to server specified in address.
61              * @param address, the server's address info.
62              * @param addressLength, length of address, structure of address can vary.
63              * @return 0 on success, -1 on error, check errno for detailed error information.
64              */
65             int Connect(const sockaddr* address, size_t addressLength);
66 
67             /**
68              * @brief An easy way to connect to host
69              * @param hostIP, a valid ipv4 or ipv6 address. The address type should match the m_addressFamily type settled during construction.
70              * Otherwise the connection will fail.
71              * @param port, the port that host listens on.
72              */
73             int ConnectToHost(const char* hostIP, unsigned short port) const;
74 
75             /**
76              * @brief An easy way to connect to 127.0.0.1 or ::1 based on m_addressFamily
77              */
78             int ConnectToLocalHost(unsigned short port) const;
79 
80             /**
81              * @brief Bind underlying udp socket to an address.
82              * @param address, the server's address info.
83              * @param addressLength, length of address, structure of address can vary.
84              * @return 0 on success, -1 on error, check errno for detailed error information.
85              */
86             int Bind(const sockaddr* address, size_t addressLength) const;
87 
88             /**
89             * @brief An easy way to bind to localhost
90             */
91             int BindToLocalHost(unsigned short port) const;
92 
93             /**
94              * @brief Send data to server without specifying address, only usable if hostIP and port are available.
95              * @param data, the data you want to send.
96              * @param dataLen, the length of data you want to send. On Windows, dataLen larger than INT32_MAX will cause undefined behavior
97              * @return 0 on success, -1 on error, check errno for detailed error information.
98              */
99             int SendData(const uint8_t* data, size_t dataLen) const;
100 
101             /**
102              * @brief Send data to server.
103              * @param address, the server's address info.
104              * @param addressLength, length of address, structure of address can vary.
105              * @param data, the memory address of the data you want to send.
106              * @param dataLen, the length of data you want to send. On Windows, dataLen larger than INT32_MAX will cause undefined behavior
107              * @return 0 on success, -1 on error check errno for detailed error information.
108              */
109             int SendDataTo(const sockaddr* address, size_t addressLength, const uint8_t* data, size_t dataLen) const;
110 
111             /**
112              * @brief An easy way to send data to localhost, when the underlying udp is connected, call this function will
113              * send the data to where it connects to, not essentially to localhost. when it's not connected, it will send data
114              * to localhost, but this call will not connect underlying socket to localhost for you.
115              * @param data, the memory address of the data you want to send.
116              * @param dataLen, the length of data you want to send. On Windows, dataLen larger than INT32_MAX will cause undefined behavior
117              * @param port, port of localhost.
118              * @return 0 on success, -1 on error, check errno for detailed error information.
119              */
120             int SendDataToLocalHost(const uint8_t* data, size_t dataLen, unsigned short port) const;
121 
122             /**
123              * @brief Receive data from unique address specified in ConnectWithServer call.
124              * this function is equivalent to call ReceiveDataFrom(nullptr, 0, data, dataLen, flags).
125              * @param buffer, the memory address where you want to store received data.
126              * @param bufferLen, the size of data buffer.
127              * @return -1 on failure, check errno for detailed error information, on success, returns the actual bytes of data received
128              */
129             int ReceiveData(uint8_t* buffer, size_t bufferLen) const;
130 
131             /**
132              * @brief Receive data from network.
133              * @param address, if not null and underlying implementation supply the incoming data's source address, this will be filled with source address info.
134              * @param addressLength, the size of source adddress, should not be null.
135              * @param buffer, the memory address where you want to store received data.
136              * @param bufferLen, the size of data buffer.
137              * @return -1 on failure, check errno for detailed error information, on success, returns the actual bytes of data received.
138              */
139             int ReceiveDataFrom(sockaddr* address, size_t* addressLength, uint8_t* buffer, size_t bufferLen) const;
140 
141             /**
142              * Gets the AddressFamily used for the underlying socket. E.g. AF_INET, AF_INET6 etc.
143              */
GetAddressFamily()144             inline int GetAddressFamily() const { return m_addressFamily; }
145 
146             /**
147              * Is the underlying socket connected with a remote address
148              */
IsConnected()149             inline bool IsConnected() const { return m_connected; }
150 
151         private:
152             void CreateSocket(int addressFamily, size_t sendBufSize, size_t receiveBufSize, bool nonBlocking);
GetUnderlyingSocket()153             int GetUnderlyingSocket() const { return m_socket; }
SetUnderlyingSocket(int socket)154             void SetUnderlyingSocket(int socket) { m_socket = socket; }
155             int m_addressFamily;
156             // if not connected, you can't perform SendData, if connected,  SendDataTo will call SendData
157             mutable bool m_connected;
158             int m_socket;
159             unsigned short m_port;
160             Aws::String m_hostIP;
161         };
162     }
163 }
164