]> git.vomp.tv Git - vompserver.git/blob - dsock.c
Compatibility for VDR 1.7.30, thanks to hondansx, Uwe and MartenR.
[vompserver.git] / dsock.c
1 /*
2     Copyright 2004-2005 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, write to the Free Software
18     Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
19 */
20
21 #include "dsock.h"
22
23 DatagramSocket::DatagramSocket()
24 {
25   addrlen = sizeof(struct sockaddr);
26   log = Log::getInstance();
27   initted = 0;
28 }
29
30 DatagramSocket::~DatagramSocket()
31 {
32   shutdown();
33 }
34
35 bool DatagramSocket::init(USHORT port)
36 {
37   myPort = port;
38   if ((socketnum = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) == -1)
39   {
40     log->log("UDP", Log::CRIT, "Socket error");
41     return false;
42   }
43
44   myAddr.sin_family = AF_INET;         // host byte order
45   myAddr.sin_port = htons(myPort);     // short, network byte order
46   myAddr.sin_addr.s_addr = INADDR_ANY; // auto-fill with my IP
47   memset(&(myAddr.sin_zero), 0, 8);    // zero the rest of the struct
48   if (bind(socketnum, (struct sockaddr *)&myAddr, addrlen) == -1)
49   {
50     log->log("UDP", Log::CRIT, "Bind error %u", myPort);
51     close(socketnum);
52     return false;
53   }
54
55   int allowed = 1;
56   setsockopt(socketnum, SOL_SOCKET, SO_BROADCAST, &allowed, sizeof(allowed));
57
58   FD_ZERO(&readfds);
59   FD_SET(socketnum, &readfds);
60   tv.tv_sec = 0;
61   tv.tv_usec = 0;
62
63   initted = 1;
64   return true;
65 }
66
67 void DatagramSocket::shutdown()
68 {
69   if (initted) close(socketnum);
70   initted = 0;
71 }
72
73 unsigned char DatagramSocket::waitforMessage(unsigned char how)
74 {
75   if (!initted) return 0;
76
77   /* how = 0 - block
78      how = 1 - start new wait
79      how = 2 - continue wait
80   */
81
82   struct timeval* passToSelect = NULL;
83
84
85   if (how == 0)
86   {
87     passToSelect = NULL;
88   }
89   else if (how == 1)
90   {
91     tv.tv_sec = 1;
92     tv.tv_usec = 100000;
93     passToSelect = &tv;
94   }
95   else if (how == 2)
96   {
97     if ((tv.tv_sec == 0) && (tv.tv_usec == 0))  // protection in case timer = 0
98     {
99       tv.tv_sec = 1;
100       tv.tv_usec = 100000;
101     }
102     passToSelect = &tv;
103   }
104   FD_ZERO(&readfds);
105   FD_SET(socketnum, &readfds);
106
107   if (select(socketnum + 1, &readfds, NULL, NULL, passToSelect) <= 0) return 1;
108
109   if ((mlength = recvfrom(socketnum, buf, MAXBUFLEN, 0, (struct sockaddr *)&theirAddr, &addrlen)) == -1)
110   {
111     log->log("UDP", Log::DEBUG, "recvfrom error");
112     return 0;
113   }
114   else
115   {
116     memset(&buf[mlength], 0, MAXBUFLEN - mlength);
117     strcpy(fromIPA, inet_ntoa(theirAddr.sin_addr));
118     fromPort = ntohs(theirAddr.sin_port);
119     //log->log("UDP", Log::DEBUG, "%s:%i received length %i", fromIPA, fromPort, mlength);
120     return 2;
121   }
122
123   /* Return 0, failure
124      Return 1, nothing happened, timer expired
125      Return 2, packet arrived (timer not expired)
126   */
127 }
128
129 void DatagramSocket::send(const char *ipa, USHORT port, char *message, int length)
130 {
131   int sentLength = 0;
132
133   //log->log("UDP", Log::DEBUG, "Send port %u", port);
134
135   theirAddr.sin_family = AF_INET;      // host byte order
136   theirAddr.sin_port = htons(port);    // short, network byte order
137   struct in_addr tad;                  // temp struct tad needed to pass to theirAddr.sin_addr
138   tad.s_addr = inet_addr(ipa);
139   theirAddr.sin_addr = tad;            // address
140   memset(&(theirAddr.sin_zero), 0, 8); // zero the rest of the struct
141
142   sentLength = sendto(socketnum, message, length, 0, (struct sockaddr *)&theirAddr, addrlen);
143   if (sentLength == length)
144   {
145     //log->log("UDP", Log::DEBUG, "%s:%u sent length %i", ipa, port, length);
146     return;
147   }
148
149   log->log("UDP", Log::DEBUG, "%s:%u send failed %i", ipa, port, length);
150
151   sentLength = sendto(socketnum, message, length, 0, (struct sockaddr *)&theirAddr, addrlen);
152   if (sentLength == length)
153   {
154     log->log("UDP", Log::DEBUG, "%s:%u sent length %i 2nd try", ipa, port, length);
155     return;
156   }
157
158   log->log("UDP", Log::DEBUG, "%s:%u send failed %i 2nd try", ipa, port, length);
159 }
160
161 ULONG DatagramSocket::getMyIP(ULONG targetIP)
162 {
163   // More friendly interface to below, takes and returns IP in network order
164
165   struct in_addr stargetIP;
166   stargetIP.s_addr = targetIP;
167   struct in_addr ret = myIPforIP(stargetIP);
168   return ret.s_addr;
169 }
170
171 struct in_addr DatagramSocket::myIPforIP(struct in_addr targetIP)
172 {
173   // This function takes a target IP on the network and returns the local IP
174   // that would be used to communicate with it.
175   // This function is static.
176
177   struct in_addr fail;
178   fail.s_addr = 0;
179
180   int zSocket;
181   if ((zSocket = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) == -1)
182   {
183     Log::getInstance()->log("UDP", Log::CRIT, "Socket error");
184     return fail;
185   }
186
187   struct sockaddr_in zTarget;
188   zTarget.sin_family = AF_INET;
189   zTarget.sin_port = htons(3024); // arbitrary
190   zTarget.sin_addr.s_addr = targetIP.s_addr;
191   memset(&(zTarget.sin_zero), 0, 8);
192
193   if (connect(zSocket, (struct sockaddr *)&zTarget, sizeof(struct sockaddr)) == -1)
194   {
195     Log::getInstance()->log("UDP", Log::CRIT, "Connect error");
196     close(zSocket);
197     return fail;
198   }
199
200   struct sockaddr_in zSource;
201   socklen_t zSourceLen = sizeof(struct sockaddr_in);
202   memset(&zSource, 0, zSourceLen);
203
204   if (getsockname(zSocket, (struct sockaddr*)&zSource, &zSourceLen) == -1)
205   {
206     Log::getInstance()->log("UDP", Log::CRIT, "Getsockname error");
207     close(zSocket);
208     return fail;
209   }
210
211   close(zSocket);
212   return zSource.sin_addr;
213 }