]> git.vomp.tv Git - vompclient.git/blob - udp4.cc
Windows fixes
[vompclient.git] / udp4.cc
1 /*
2     Copyright 2004-2020 Chris Tallon
3
4     This file is part of VOMP.
5
6     VOMP is free software; you can redistribute it and/or modify
7     it under the terms of the GNU General Public License as published by
8     the Free Software Foundation; either version 2 of the License, or
9     (at your option) any later version.
10
11     VOMP is distributed in the hope that it will be useful,
12     but WITHOUT ANY WARRANTY; without even the implied warranty of
13     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14     GNU General Public License for more details.
15
16     You should have received a copy of the GNU General Public License
17     along with VOMP.  If not, see <https://www.gnu.org/licenses/>.
18 */
19
20 #ifndef WIN32
21 #include <netdb.h>
22 #include <unistd.h>
23 #include <arpa/inet.h>
24 #include <sys/time.h>
25 #define SOCKET_ERROR 0
26 #else
27 #include <winsock2.h>
28 #include <Ws2tcpip.h>
29 #include <sys/timeb.h>
30 #endif
31
32 #include <sys/types.h>
33 #include <stdio.h>
34 #include <stdlib.h>
35 #include <string.h>
36 #include <errno.h>
37
38 #include "defines.h"
39 #include "log.h"
40
41 #include "udp4.h"
42
43 UDP4::~UDP4()
44 {
45   if (initted) shutdown();
46 }
47
48 int UDP4::init(USHORT tport)
49 {
50   if (initted) return 0;
51   
52   myPort = tport;
53   addrlen = sizeof(struct sockaddr);
54
55   if ((socketnum = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) == -1)
56   { perror("socket"); return 0; }
57
58   myAddr.sin_family = AF_INET;         // host byte order
59   myAddr.sin_port = htons(myPort);     // short, network byte order
60   myAddr.sin_addr.s_addr = getIPNumber(iterate_ip++); // auto-fill with my IP
61   memset(&(myAddr.sin_zero), 0, 8);    // zero the rest of the struct
62
63   if (bind(socketnum, reinterpret_cast<struct sockaddr *>(&myAddr), addrlen) == -1)
64   { perror("bind"); return 0; }
65
66   FD_ZERO(&readfds);
67   FD_SET(socketnum, &readfds);
68   tv.tv_sec = 0;
69   tv.tv_usec = 0;
70
71   int allowed = 1;
72
73 #ifdef WIN32
74   setsockopt(socketnum, SOL_SOCKET, SO_BROADCAST, reinterpret_cast<char*>(&allowed), sizeof(allowed));
75 #else
76   setsockopt(socketnum, SOL_SOCKET, SO_BROADCAST, static_cast<void*>(&allowed), sizeof(allowed));
77 #endif
78
79   initted = true;
80
81   return 1;
82 }
83
84 void UDP4::shutdown()
85 {
86   if (!initted) return;
87   CLOSESOCKET(socketnum);
88   initted = false;
89 }
90
91 #ifdef WIN32
92 unsigned char UDP4::waitforMessage(unsigned char how, SOCKET quitPipe)
93 #else
94 unsigned char UDP4::waitforMessage(unsigned char how, int quitPipe)
95 #endif
96 {
97   if (!initted) return 0;
98
99   /* how = 0 - block
100      how = 1 - start new wait
101      how = 2 - continue wait
102      how = 3 - block, return on byte from quitPipe
103   */
104
105   FD_ZERO(&readfds);
106   FD_SET(socketnum, &readfds);
107
108   struct timeval* passToSelect = NULL;
109
110   int sockMaxP1 = socketnum + 1;
111
112   if (how == 1)
113   {
114     tv.tv_sec = 1;
115     tv.tv_usec = 500000;
116     passToSelect = &tv;
117   }
118   else if (how == 2)
119   {
120     if ((tv.tv_sec == 0) && (tv.tv_usec == 0))  // protection in case timer = 0
121     {
122       tv.tv_sec = 1;
123       tv.tv_usec = 500000;
124     }
125     passToSelect = &tv;
126   }
127   else if (how == 3)
128   {
129     FD_SET(quitPipe, &readfds);
130     if (quitPipe > socketnum) sockMaxP1 = quitPipe + 1;
131   }
132
133
134   if (select(sockMaxP1, &readfds, NULL, NULL, passToSelect) <= 0)
135   {  return 1;  }
136
137   if ((how == 3) && FD_ISSET(quitPipe, &readfds)) return 3;
138
139   if ((mlength = recvfrom(socketnum, buf, MAXBUFLEN, 0,
140       reinterpret_cast<struct sockaddr *>(&theirAddr), &addrlen)) == -1)
141   { perror("recvfrom"); return 0; }
142   else
143   {
144     memset(&buf[mlength], 0, MAXBUFLEN - mlength);
145     strcpy(fromIPA, inet_ntoa(theirAddr.sin_addr));
146     fromPort = ntohs(theirAddr.sin_port);
147
148     return 2;
149   }
150
151   /* Return 0, failure
152      Return 1, nothing happened, timer expired
153      Return 2, packet arrived (timer not expired)
154   */
155 }
156
157 UINT UDP4::getDataLength(void) const
158 {
159   return static_cast<UINT>(mlength);
160 }
161
162 const void* UDP4::getData() const     {  return buf;  }
163 const char* UDP4::getFromIPA() const  {  return fromIPA;  }
164 short UDP4::getFromPort() const       {  return fromPort; }
165
166 bool UDP4::send(const char *ipa, USHORT port, char *message, int length)
167 {
168   if (!initted) return false;
169
170   int sentLength = 0;
171
172   struct sockaddr_in sendAddr;
173   sendAddr.sin_family = AF_INET;      // host byte order
174   sendAddr.sin_port = htons(port);    // short, network byte order
175   struct in_addr tad;                 // temp struct tad needed to pass to sendAddr.sin_addr
176   tad.s_addr = inet_addr(ipa);
177   sendAddr.sin_addr = tad;            // address
178   memset(&(sendAddr.sin_zero), 0, 8); // zero the rest of the struct
179
180   errno = 0;
181
182   sentLength = sendto(socketnum, message, length, 0, reinterpret_cast<struct sockaddr *>(&sendAddr), addrlen);
183   if (sentLength == length) return true;
184   Log::getInstance()->log("UDP6", Log::ERR, "sendto failed, errno = %i", errno);
185   return false;
186 }
187
188 #ifndef WIN32
189 ULONG UDP4::getIPNumber(ULONG)
190 {
191   return INADDR_ANY;
192 }
193 #else
194 ULONG UDP4::getIPNumber(ULONG num)
195 {
196   char buffer[100];
197   ULONG returnaddress;
198
199   if (gethostname(buffer,sizeof(buffer))==SOCKET_ERROR)
200   {
201     return INADDR_ANY; //well take any address, if we fail
202   }
203
204   struct hostent *hosts=gethostbyname(buffer);
205   if (hosts==NULL)
206   {
207     return INADDR_ANY; //well take any address, if we fail
208   }
209
210   int num_ip=0;
211   for (num_ip=0;hosts->h_addr_list[num_ip]!=NULL;num_ip++);
212
213   int get_ip=(num%num_ip);//Just wrap around, if no interface are present any more
214   memcpy(&returnaddress, hosts->h_addr_list[get_ip], sizeof(ULONG));
215   return returnaddress;
216 }
217 #endif