From 51e61e39733931aee54ae23ab4eb16917cb1325e Mon Sep 17 00:00:00 2001 From: Justin Maggard Date: Fri, 31 Jul 2009 01:41:10 +0000 Subject: [PATCH] * Track MAC addresses in the client cache (when we can find them); so if we have an expired cache entry, but the MAC hasn't changed, we can assume the original ID is still valid. --- getifaddr.c | 35 +++++++++++++++++++++++++++++++++++ getifaddr.h | 4 ++++ minidlnatypes.h | 1 + upnphttp.c | 33 ++++++++++++++++++++++++++------- 4 files changed, 66 insertions(+), 7 deletions(-) diff --git a/getifaddr.c b/getifaddr.c index 18a5daf..35d3a3b 100644 --- a/getifaddr.c +++ b/getifaddr.c @@ -127,3 +127,38 @@ getifhwaddr(const char * ifname, char * buf, int len) } return 0; } + +int +get_remote_mac(struct in_addr ip_addr, unsigned char * mac) +{ + struct in_addr arp_ent; + FILE * arp; + char remote_ip[16]; + int matches, hwtype, flags; + memset(mac, 0xFF, 6); + + arp = fopen("/proc/net/arp", "r"); + if( !arp ) + return 1; + while( !feof(arp) ) + { + matches = fscanf(arp, "%s 0x%X 0x%X %hhx:%hhx:%hhx:%hhx:%hhx:%hhx", + remote_ip, &hwtype, &flags, + &mac[0], &mac[1], &mac[2], &mac[3], &mac[4], &mac[5]); + if( matches != 9 ) + continue; + inet_pton(AF_INET, remote_ip, &arp_ent); + if( ip_addr.s_addr == arp_ent.s_addr ) + break; + mac[0] = 0xFF; + } + fclose(arp); + + if( mac[0] == 0xFF ) + { + memset(mac, 0xFF, 6); + return 1; + } + + return 0; +} diff --git a/getifaddr.h b/getifaddr.h index 65a7668..d6651ad 100644 --- a/getifaddr.h +++ b/getifaddr.h @@ -6,6 +6,7 @@ #ifndef __GETIFADDR_H__ #define __GETIFADDR_H__ +#include /* getifaddr() * take a network interface name and write the @@ -20,5 +21,8 @@ getsysaddr(char * buf, int len); int getifhwaddr(const char * ifname, char * buf, int len); +int +get_remote_mac(struct in_addr ip_addr, unsigned char * mac); + #endif diff --git a/minidlnatypes.h b/minidlnatypes.h index 6560ca8..ec4f72b 100644 --- a/minidlnatypes.h +++ b/minidlnatypes.h @@ -58,6 +58,7 @@ struct album_art_name_s { struct client_cache_s { struct in_addr addr; + unsigned char mac[6]; enum client_types type; u_int32_t flags; time_t age; diff --git a/upnphttp.c b/upnphttp.c index 4486c04..40dbbf3 100644 --- a/upnphttp.c +++ b/upnphttp.c @@ -30,9 +30,11 @@ #include #include #include +#include #include "upnpglobalvars.h" #include "utils.h" +#include "getifaddr.h" #include "image_utils.h" #include "log.h" #include "sql.h" @@ -94,11 +96,22 @@ SearchClientCache(struct in_addr addr) { if( clients[i].addr.s_addr == addr.s_addr ) { - /* Invalidate this client cache if it's older than 2 hours */ - if( (time(NULL) - clients[i].age) > 7200 ) + /* Invalidate this client cache if it's older than 1 hour */ + if( (time(NULL) - clients[i].age) > 3600 ) { - memset(&clients[i], 0, sizeof(struct client_cache_s)); - return -1; + unsigned char mac[6]; + if( get_remote_mac(addr, mac) == 0 && + memcmp(mac, clients[i].mac, 6) == 0 ) + { + /* Same MAC as last time when we were able to identify the client, + * so extend the timeout by another hour. */ + clients[i].age = time(NULL); + } + else + { + memset(&clients[i], 0, sizeof(struct client_cache_s)); + return -1; + } } DPRINTF(E_DEBUG, L_HTTP, "Client found in cache. [type %d/entry %d]\n", clients[i].type, i); return i; @@ -350,6 +363,9 @@ next_header: h->req_chunklen = -1; } } + /* Don't bother checking client type until we have the whole request. */ + if( (h->req_buflen - h->req_contentoff) < h->req_contentlen ) + return; /* If the client type wasn't found, search the cache. * This is done because a lot of clients like to send a * different User-Agent with different types of requests. */ @@ -363,15 +379,18 @@ next_header: { if( clients[n].addr.s_addr ) continue; + get_remote_mac(h->clientaddr, clients[n].mac); clients[n].addr = h->clientaddr; - DPRINTF(E_DEBUG, L_HTTP, "Added client [%d/%X] to cache slot %d.\n", - h->req_client, clients[n].addr.s_addr, n); + DPRINTF(E_DEBUG, L_HTTP, "Added client [%d/%s/%02X:%02X:%02X:%02X:%02X:%02X] to cache slot %d.\n", + h->req_client, inet_ntoa(clients[n].addr), + clients[n].mac[0], clients[n].mac[1], clients[n].mac[2], + clients[n].mac[3], clients[n].mac[4], clients[n].mac[5], n); break; } } else if( (n < EStandardDLNA150) && (h->req_client == EStandardDLNA150) ) { - /* If we know the client, but our new detection is generic, use our cached info */ + /* If we know the client and our new detection is generic, use our cached info */ h->reqflags |= clients[n].flags; h->req_client = clients[n].type; return;