Merge remote branch 'remotes/origin/Teaman-IPTraffic' into Teaman-ND
[tomato.git] / release / src / router / minidlna / tivo_beacon.c
blob6c5273e93c7e90af016c2c0ab327ccebfcbec5ce
1 /*
2 * Linux/C based server for TiVo Home Media Option protocol
4 * Based on version 1.5.1 of
5 * "TiVo Connect Automatic Machine; Discovery Protocol Specification"
6 * Based on version 1.1.0 of
7 * "TiVo Home Media Option; Music and Photos Server Protocol Specification"
9 * Dave Clemans, April 2003
11 * byRequest TiVo HMO Server
12 * Copyright (C) 2003 Dave Clemans
14 * This file is based on byRequest, and is part of MiniDLNA.
16 * byRequest is free software; you can redistribute it and/or modify
17 * it under the terms of the GNU General Public License as published by
18 * the Free Software Foundation; either version 2 of the License, or
19 * (at your option) any later version.
21 * byRequest is distributed in the hope that it will be useful,
22 * but WITHOUT ANY WARRANTY; without even the implied warranty of
23 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
24 * GNU General Public License for more details.
26 * You should have received a copy of the GNU General Public License
27 * along with byRequest. If not, see <http://www.gnu.org/licenses/>.
29 #include "config.h"
30 #ifdef TIVO_SUPPORT
31 #include <stdlib.h>
32 #include <stdio.h>
33 #include <unistd.h>
34 #include <string.h>
35 #include <sys/wait.h>
36 #include <sys/ioctl.h>
37 #include <sys/stat.h>
38 #include <fcntl.h>
39 #include <errno.h>
40 #include <time.h>
42 #include <sys/param.h>
43 #include <sys/socket.h>
44 #include <netinet/in.h>
45 #include <arpa/inet.h>
46 #include <net/if.h>
47 #include <sys/poll.h>
48 #include <netdb.h>
50 #include "tivo_beacon.h"
51 #include "upnpglobalvars.h"
52 #include "log.h"
54 static struct aBeacon* topBeacon = NULL;
56 /* OpenAndConfHTTPSocket() :
57 * setup the socket used to handle incoming HTTP connections. */
58 int
59 OpenAndConfTivoBeaconSocket()
61 int s;
62 int i = 1;
63 struct sockaddr_in beacon;
65 if( (s = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0)
67 DPRINTF(E_ERROR, L_TIVO, "socket(http): %s\n", strerror(errno));
68 return -1;
71 if(setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &i, sizeof(i)) < 0)
73 DPRINTF(E_WARN, L_TIVO, "setsockopt(http, SO_REUSEADDR): %s\n", strerror(errno));
76 memset(&beacon, 0, sizeof(struct sockaddr_in));
77 beacon.sin_family = AF_INET;
78 beacon.sin_port = htons(2190);
79 beacon.sin_addr.s_addr = htonl(INADDR_ANY);
81 if(bind(s, (struct sockaddr *)&beacon, sizeof(struct sockaddr_in)) < 0)
83 DPRINTF(E_ERROR, L_TIVO, "bind(http): %s\n", strerror(errno));
84 close(s);
85 return -1;
87 i = 1;
88 if(setsockopt(s, SOL_SOCKET, SO_BROADCAST, &i, sizeof(i)) < 0 )
90 DPRINTF(E_WARN, L_TIVO, "setsockopt(http, SO_BROADCAST): %s\n", strerror(errno));
91 close(s);
92 return -1;
95 return s;
99 * Returns the interface broadcast address to be used for beacons
101 uint32_t
102 getBcastAddress(void)
104 int i, rval;
105 int s = socket(PF_INET, SOCK_STREAM, 0);
106 struct sockaddr_in sin;
107 struct sockaddr_in addr;
108 struct ifreq ifr;
110 for (i=1; i > 0; i++)
112 ifr.ifr_ifindex = i;
113 if( ioctl(s, SIOCGIFNAME, &ifr) < 0 )
114 break;
115 if(ioctl(s, SIOCGIFADDR, &ifr, sizeof(struct ifreq)) < 0)
116 continue;
117 memcpy(&addr, &ifr.ifr_addr, sizeof(addr));
118 if(strcmp(inet_ntoa(addr.sin_addr), lan_addr[0].str) == 0)
120 rval = ioctl(s, SIOCGIFBRDADDR, &ifr);
121 if( rval < 0 )
123 close(s);
124 return INADDR_BROADCAST;
126 memcpy(&sin, &ifr.ifr_broadaddr, sizeof(sin));
127 close(s);
128 DPRINTF(E_DEBUG, L_TIVO, "Interface: %s broadcast addr %s \n", ifr.ifr_name, inet_ntoa(sin.sin_addr));
129 return ntohl((uint32_t)(sin.sin_addr.s_addr));
133 return INADDR_BROADCAST;
137 * Send outgoing beacon to the specified address
138 * This will either be a specific or broadcast address
140 void
141 sendBeaconMessage(int fd, struct sockaddr_in * client, int len, int broadcast)
143 char * mesg;
144 int mesg_len;
146 mesg_len = asprintf(&mesg, "TiVoConnect=1\n"
147 "swversion=%s\n"
148 "method=%s\n"
149 "identity=%s\n"
150 "machine=%s\n"
151 "platform=pc/minidlna\n"
152 "services=TiVoMediaServer:%d/http\n",
153 "1.0",
154 broadcast ? "broadcast" : "connected",
155 uuidvalue, friendly_name, runtime_vars.port);
156 DPRINTF(E_DEBUG, L_TIVO, "Sending TiVo beacon\n");
157 sendto(fd, mesg, mesg_len, 0, (struct sockaddr*)client, len);
158 free(mesg);
162 * Parse and save a received beacon packet from another server, or from
163 * a TiVo.
165 * Returns true if this was a broadcast beacon msg
168 rcvBeaconMessage(char * beacon)
170 char * tivoConnect = NULL;
171 char * swVersion = NULL;
172 char * method = NULL;
173 char * identity = NULL;
174 char * machine = NULL;
175 char * platform = NULL;
176 char * services = NULL;
177 char * cp;
178 char * scp;
179 char * tokptr;
180 struct aBeacon * b;
181 int len;
182 time_t current;
183 char buf[32];
184 static time_t lastSummary = 0;
186 cp = strtok_r( beacon, "=\r\n", &tokptr );
187 while( cp != NULL )
189 scp = cp;
190 cp = strtok_r( NULL, "=\r\n", &tokptr );
191 if( strcasecmp( scp, "tivoconnect" ) == 0 )
192 tivoConnect = cp;
193 else if( strcasecmp( scp, "swversion" ) == 0 )
194 swVersion = cp;
195 else if( strcasecmp( scp, "method" ) == 0 )
196 method = cp;
197 else if( strcasecmp( scp, "identity" ) == 0 )
198 identity = cp;
199 else if( strcasecmp( scp, "machine" ) == 0 )
200 machine = cp;
201 else if( strcasecmp( scp, "platform" ) == 0 )
202 platform = cp;
203 else if( strcasecmp( scp, "services" ) == 0 )
204 services = cp;
205 cp = strtok_r( NULL, "=\r\n", &tokptr );
208 if( tivoConnect == NULL )
209 return 0;
211 current = time( NULL );
212 for( b = topBeacon; b != NULL; b = b->next )
214 if( strcasecmp( machine, b->machine ) == 0 ||
215 strcasecmp( identity, b->identity ) == 0 )
217 break;
220 if( b == NULL )
222 b = ( struct aBeacon* ) calloc( 1, sizeof( *b ) );
223 b->next = NULL;
225 if ( machine )
227 b->machine = ( char* ) malloc( strlen( machine ) + 1 );
228 strcpy( b->machine, machine );
230 if ( identity )
232 b->identity = ( char* ) malloc( strlen( identity ) + 1 );
233 strcpy( b->identity, identity );
235 if ( swVersion )
237 b->swversion = ( char* ) malloc( strlen( swVersion ) + 1 );
238 strcpy( b->swversion, swVersion );
240 if ( method )
242 b->method = ( char* ) malloc( strlen( method ) + 1 );
243 strcpy( b->method, method );
245 if ( platform )
247 b->platform = ( char* ) malloc( strlen( platform ) + 1 );
248 strcpy( b->platform, platform );
250 if ( services )
252 b->services = ( char* ) malloc( strlen( services ) + 1 );
253 strcpy( b->services, services );
256 b->next = topBeacon;
257 topBeacon = b;
259 printf( "Received new beacon: machine(%s) platform(%s) services(%s)\n",
260 b->machine ? b->machine : "-",
261 b->platform ? b->platform : "-",
262 b->services ? b->services : "-" );
264 b->lastSeen = current;
266 if( lastSummary == 0 )
267 lastSummary = current;
268 if( lastSummary + 1800 < current )
269 { /* Give a summary of received server beacons every half hour or so */
270 len = 0;
271 for( b = topBeacon; b != NULL; b = b->next )
273 len += strlen( b->machine ) + 32;
275 scp = ( char* ) malloc( len + 128 );
276 strcpy( scp, "Known servers: " );
277 for( b = topBeacon; b != NULL; b = b->next )
279 strcat( scp, b->machine );
280 sprintf( buf, "(%ld)", current - b->lastSeen );
281 strcat( scp, buf );
282 if( b->next != NULL )
283 strcat( scp, "," );
285 strcat(scp, "\n");
286 printf("%s\n", scp);
287 free(scp);
288 lastSummary = current;
291 if( strcasecmp( method, "broadcast" ) == 0 )
292 return 1;
293 return 0;
295 #endif // TIVO_SUPPORT