MySensors Library & Examples  2.3.2-62-ge298769
UDPHelper_POSIX.h
1 #pragma once
2 
3 #include <stdio.h>
4 #include <errno.h>
5 
6 #ifdef _WIN32
7 #include <winsock2.h>
8 #include <WS2tcpip.h>
9 
10 #define close(fd) closesocket(fd)
11 #define ssize_t int
12 #else
13 #include <sys/time.h>
14 #include <string.h>
15 #include <unistd.h>
16 #include <netdb.h>
17 #include <sys/socket.h>
18 #include <netinet/in.h>
19 #include <arpa/inet.h>
20 #endif
21 
22 #ifdef __ZEPHYR__
23 #include <fcntl.h>
24 #define INADDR_BROADCAST ((u32_t) 0xffffffff)
25 #endif
26 
27 class UDPHelper
28 {
29  uint16_t _port;
30  uint32_t _magic_header;
31  sockaddr_in _localaddr, _remote_receiver_addr, _remote_sender_addr;
32  int _fd = -1;
33 public:
34  ~UDPHelper()
35  {
36  if (_fd != -1)
37 #ifdef _WIN32
38  closesocket(_fd);
39  WSACleanup();
40 #else
41  close(_fd);
42 #endif
43  }
44 
45  bool begin(uint16_t port)
46  {
47 #ifdef _WIN32
48  // Initialize Winsock
49  WSAData wsaData;
50  int iResult;
51  iResult = WSAStartup(MAKEWORD(2, 2), &wsaData);
52  if (iResult != 0) {
53  return false;
54  }
55 #endif
56  _port = port;
57 
58  // Close if open after previous init attempt
59  if (_fd != -1) {
60 #ifdef _WIN32
61  closesocket(_fd);
62 #else
63  close(_fd);
64 #endif
65  _fd = -1;
66  }
67 
68  // Prepare socket
69  _fd=socket(AF_INET,SOCK_DGRAM, IPPROTO_UDP);
70  if (_fd==-1) {
71  //printf("INIT listening socket %s\n", strerror(errno));
72  return false;
73  }
74 
75  // Make it non-blocking
76 #ifdef _WIN32
77  DWORD read_timeout = 10; // millis
78 #else
79  struct timeval read_timeout;
80  read_timeout.tv_sec = 0;
81  read_timeout.tv_usec = 1000;
82 #endif
83 #ifdef __ZEPHYR__
84  fcntl(_fd, F_SETFL, O_NONBLOCK);
85 #else
86  setsockopt(_fd, SOL_SOCKET, SO_RCVTIMEO, (char *)&read_timeout, sizeof read_timeout);
87 #endif
88 
89  // Bind to specific local port
90  memset(&_localaddr, 0, sizeof(_localaddr));
91  _localaddr.sin_family = AF_INET;
92  _localaddr.sin_port = htons(_port);
93  _localaddr.sin_addr.s_addr = INADDR_ANY;
94  if (bind(_fd,(struct sockaddr *) &_localaddr,sizeof(_localaddr))==-1) {
95  //printf("INIT listening bind %s\n", strerror(errno));
96  return false;
97  }
98  memset(&_remote_sender_addr, 0, sizeof(_remote_sender_addr));
99 
100  // Prepare receiver address as broadcast
101  memset(&_remote_receiver_addr, 0, sizeof(_remote_receiver_addr));
102  _remote_receiver_addr.sin_family = AF_INET;
103  _remote_receiver_addr.sin_port = htons(_port);
104  _remote_receiver_addr.sin_addr.s_addr = INADDR_BROADCAST;
105 
106 #ifndef __ZEPHYR__
107  // Allow broadcasts
108  int broadcast=1;
109  if (setsockopt(_fd,SOL_SOCKET,SO_BROADCAST,(const char*)&broadcast,sizeof(broadcast))==-1) {
110  //printf("INIT send setsockopt %s\n", strerror(errno));
111  return false;
112  }
113 #endif
114  return true;
115  }
116 
117  uint16_t receive_frame(uint8_t *string, uint16_t max_length)
118  {
119  struct sockaddr_storage src_addr;
120  socklen_t src_addr_len=sizeof(src_addr);
121  ssize_t count=recvfrom(_fd,(char*)string,max_length,0,(struct sockaddr*)&src_addr,&src_addr_len);
122  if (count==-1) {
123 #ifdef _WIN32
124  //int error = WSAGetLastError();
125  //if (error != WSAETIMEDOUT) printf("recvfrom error %d, bufsize=%d\n", error, max_length);
126 #endif
127  return false; // Reception failed
128  } else if (count==max_length || count < 4) {
129  //printf("FAIL receive_frame recvfrom %d\n", count);
130  return false; // Too large packet
131  } else {
132  //printf("OK receive_frame recvfrom %d, maxize %d\n", count, max_length);
133  // Remember sender's address
134  memcpy(&_remote_sender_addr, &src_addr, sizeof(_remote_sender_addr));
135 
136  // Get header
137  uint32_t header = 0;
138  memcpy(&header, string, 4);
139  if(header != _magic_header) {
140  return false; // Not a LocalUDP packet
141  }
142 
143  // Shift contents to remove header
144  for (uint16_t i=0; i<count-4; i++) {
145  string[i] = string[i+4];
146  }
147  return count - 4;
148  }
149  return PJON_FAIL;
150  }
151 
152  class Buf
153  {
154  char *buf = NULL;
155  uint16_t len = 0;
156  public:
157  Buf(uint16_t size)
158  {
159  len = size;
160  buf = new char[size];
161  }
162  ~Buf()
163  {
164  if (buf) {
165  delete[] buf;
166  }
167  }
168  char* operator()()
169  {
170  return buf;
171  }
172  uint16_t size()
173  {
174  return len;
175  }
176  };
177 
178 
179  void send_frame(const uint8_t *string, uint16_t length, const sockaddr_in &remote_addr)
180  {
181  if(length > 0) {
182  Buf buffer(4 + length);
183  memcpy(buffer(), &_magic_header, 4);
184  memcpy(&(buffer()[4]), string, length);
185  int res = sendto(_fd,buffer(),buffer.size(),0,(const sockaddr *)&remote_addr,sizeof(remote_addr));
186  //printf("send_frame %d sendto %d\n", length, res);
187  }
188  }
189 
190  void send_response(uint8_t *string, uint16_t length)
191  {
192  send_frame((const uint8_t *)string, length, _remote_sender_addr);
193  }
194 
195  void send_response(uint8_t response)
196  {
197  send_frame((const uint8_t *)&response, 1, _remote_sender_addr);
198  }
199 
200  void send_frame(const uint8_t *string, uint16_t length)
201  {
202  _remote_receiver_addr.sin_port = htons(_port);
203  _remote_receiver_addr.sin_addr.s_addr = INADDR_BROADCAST;
204  send_frame(string, length, _remote_receiver_addr);
205  }
206 
207  void send_frame(const uint8_t *string, uint16_t length, uint8_t *remote_ip, uint16_t remote_port)
208  {
209  _remote_receiver_addr.sin_port = htons(remote_port);
210  _remote_receiver_addr.sin_addr.s_addr = *(uint32_t*)remote_ip;
211  send_frame(string, length, _remote_receiver_addr);
212  }
213 
214  void set_magic_header(uint32_t magic_header)
215  {
216  _magic_header = magic_header;
217  }
218 
219  void get_sender(uint8_t *ip, uint16_t &port)
220  {
221  memcpy(ip, &_remote_sender_addr.sin_addr.s_addr, 4);
222  port = ntohs(_remote_sender_addr.sin_port);
223  }
224 };
225 
226 #undef close
UDPHelper::Buf
Definition: UDPHelper_POSIX.h:152
UDPHelper
Definition: UDPHelper_ARDUINO.h:21