summaryrefslogtreecommitdiffstats
path: root/src/UDPClient/UDPClient.cpp
blob: 844b7f9a10f02846fa0fbce1c7847d9fbff9712e (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
/*
 * http://linux.m2osw.com/c-implementation-udp-clientserver
 *
 * UDPSender.cpp
 *
 *  Created on: 29.06.2016
 *      Author: Tobias Frust
 */

 // ========================= CLIENT =========================

 /** \brief Initialize a UDP client object.
  *
  * This function initializes the UDP client object using the address and the
  * port as specified.
  *
  * The port is expected to be a host side port number (i.e. 59200).
  *
  * The \p addr parameter is a textual address. It may be an IPv4 or IPv6
  * address and it can represent a host name or an address defined with
  * just numbers. If the address cannot be resolved then an error occurs
  * and constructor throws.
  *
  * \note
  * The socket is open in this process. If you fork() or exec() then the
  * socket will be closed by the operating system.
  *
  * \warning
  * We only make use of the first address found by getaddrinfo(). All
  * the other addresses are ignored.
  *
  * \exception udp_client_server_runtime_error
  * The server could not be initialized properly. Either the address cannot be
  * resolved, the port is incompatible or not available, or the socket could
  * not be created.
  *
  * \param[in] addr  The address to convert to a numeric IP.
  * \param[in] port  The port number.
  */

#include "UDPClient.h"

#include <string.h>
#include <unistd.h>

#ifndef SOCK_CLOEXEC
#define SOCK_CLOEXEC 0
#endif

 UDPClient::UDPClient(const std::string& addr, int port)
     : f_port(port)
     , f_addr(addr){
     char decimal_port[16];
     snprintf(decimal_port, sizeof(decimal_port), "%d", f_port);
     decimal_port[sizeof(decimal_port) / sizeof(decimal_port[0]) - 1] = '\0';
     struct addrinfo hints;
     memset(&hints, 0, sizeof(hints));
     hints.ai_family = AF_UNSPEC;
     hints.ai_socktype = SOCK_DGRAM;
     hints.ai_protocol = IPPROTO_UDP;
     int r(getaddrinfo(addr.c_str(), decimal_port, &hints, &f_addrinfo));
     if(r != 0 || f_addrinfo == NULL)
     {
         throw udp_client_server_runtime_error(("invalid address or port: \"" + addr + ":" + decimal_port + "\"").c_str());
     }
     f_socket = socket(f_addrinfo->ai_family, SOCK_DGRAM | SOCK_CLOEXEC, IPPROTO_UDP);
     if(f_socket == -1)
     {
         freeaddrinfo(f_addrinfo);
         throw udp_client_server_runtime_error(("could not create socket for: \"" + addr + ":" + decimal_port + "\"").c_str());
     }
 }

 /** \brief Clean up the UDP client object.
  *
  * This function frees the address information structure and close the socket
  * before returning.
  */
 UDPClient::~UDPClient()
 {
     freeaddrinfo(f_addrinfo);
     close(f_socket);
 }

 /** \brief Retrieve a copy of the socket identifier.
  *
  * This function return the socket identifier as returned by the socket()
  * function. This can be used to change some flags.
  *
  * \return The socket used by this UDP client.
  */
 int UDPClient::get_socket() const {
     return f_socket;
 }

 /** \brief Retrieve the port used by this UDP client.
  *
  * This function returns the port used by this UDP client. The port is
  * defined as an integer, host side.
  *
  * \return The port as expected in a host integer.
  */
 int UDPClient::get_port() const {
     return f_port;
 }

 /** \brief Retrieve a copy of the address.
  *
  * This function returns a copy of the address as it was specified in the
  * constructor. This does not return a canonalized version of the address.
  *
  * The address cannot be modified. If you need to send data on a different
  * address, create a new UDP client.
  *
  * \return A string with a copy of the constructor input address.
  */
 std::string UDPClient::get_addr() const {
     return f_addr;
 }

 /** \brief Send a message through this UDP client.
  *
  * This function sends \p msg through the UDP client socket. The function
  * cannot be used to change the destination as it was defined when creating
  * the udp_client object.
  *
  * The size must be small enough for the message to fit. In most cases we
  * use these in Snap! to send very small signals (i.e. 4 bytes commands.)
  * Any data we would want to share remains in the Cassandra database so
  * that way we can avoid losing it because of a UDP message.
  *
  * \param[in] msg  The message to send.
  * \param[in] size  The number of bytes representing this message.
  *
  * \return -1 if an error occurs, otherwise the number of bytes sent. errno
  * is set accordingly on error.
  */
 int UDPClient::send(const char *msg, std::size_t size){
     return sendto(f_socket, msg, size, 0, f_addrinfo->ai_addr, f_addrinfo->ai_addrlen);
 }