1/* MiniDLNA media server 2 * Copyright (C) 2013 NETGEAR 3 * 4 * This file is part of MiniDLNA. 5 * 6 * MiniDLNA is free software; you can redistribute it and/or modify 7 * it under the terms of the GNU General Public License version 2 as 8 * published by the Free Software Foundation. 9 * 10 * MiniDLNA is distributed in the hope that it will be useful, 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 * GNU General Public License for more details. 14 * 15 * You should have received a copy of the GNU General Public License 16 * along with MiniDLNA. If not, see <http://www.gnu.org/licenses/>. 17 */ 18#include <stdio.h> 19#include <string.h> 20#include <time.h> 21 22#include "clients.h" 23#include "getifaddr.h" 24#include "log.h" 25 26struct client_type_s client_types[] = 27{ 28 { 0, 29 0, 30 "Unknown", 31 NULL, 32 EMatchNone 33 }, 34 35 { EXbox, 36 FLAG_MIME_AVI_AVI | FLAG_MS_PFS, 37 "Xbox 360", 38 "Xbox/", 39 EUserAgent 40 }, 41 42 { EPS3, 43 FLAG_DLNA | FLAG_MIME_AVI_DIVX, 44 "PLAYSTATION 3", 45 "PLAYSTATION", 46 EUserAgent 47 }, 48 49 { EPS3, 50 FLAG_DLNA | FLAG_MIME_AVI_DIVX, 51 "PLAYSTATION 3", 52 "PLAYSTATION 3", 53 EXAVClientInfo 54 }, 55 56 /* Samsung Series [CDE] BDPs and TVs must be separated, or some of our 57 * advertised extra features trigger a folder browsing bug on BDPs. */ 58 /* User-Agent: DLNADOC/1.50 SEC_HHP_BD-D5100/1.0 */ 59 { ESamsungSeriesCDEBDP, 60 FLAG_SAMSUNG | FLAG_DLNA | FLAG_NO_RESIZE, 61 "Samsung Series [CDEF] BDP", 62 "SEC_HHP_BD", 63 EUserAgent 64 }, 65 66 /* User-Agent: DLNADOC/1.50 SEC_HHP_[TV]UE40D7000/1.0 */ 67 /* User-Agent: DLNADOC/1.50 SEC_HHP_ Family TV/1.0 */ 68 { ESamsungSeriesCDE, 69 FLAG_SAMSUNG | FLAG_DLNA | FLAG_NO_RESIZE | FLAG_SAMSUNG_DCM10, 70 "Samsung Series [CDEF]", 71 "SEC_HHP_", 72 EUserAgent 73 }, 74 75 { ESamsungSeriesA, 76 FLAG_SAMSUNG | FLAG_DLNA | FLAG_NO_RESIZE, 77 "Samsung Series A", 78 "SamsungWiselinkPro", 79 EUserAgent 80 }, 81 82 { ESamsungSeriesB, 83 FLAG_SAMSUNG | FLAG_DLNA | FLAG_NO_RESIZE, 84 "Samsung Series B", 85 "Samsung DTV DMR", 86 EModelName 87 }, 88 89 /* User-Agent: Panasonic MIL DLNA CP UPnP/1.0 DLNADOC/1.50 */ 90 { EPanasonic, 91 FLAG_DLNA | FLAG_FORCE_SORT, 92 "Panasonic", 93 "Panasonic", 94 EUserAgent 95 }, 96 97 /* User-Agent: IPI/1.0 UPnP/1.0 DLNADOC/1.50 */ 98 { ENetFrontLivingConnect, 99 FLAG_DLNA | FLAG_FORCE_SORT | FLAG_CAPTION_RES, 100 "NetFront Living Connect", 101 "IPI/1", 102 EUserAgent 103 }, 104 105 { EDenonReceiver, 106 FLAG_DLNA, 107 "Denon Receiver", 108 "bridgeCo-DMP/3", 109 EUserAgent 110 }, 111 112 { EFreeBox, 113 FLAG_RESIZE_THUMBS, 114 "FreeBox", 115 "fbxupnpav/", 116 EUserAgent 117 }, 118 119 { EPopcornHour, 120 FLAG_MIME_FLAC_FLAC, 121 "Popcorn Hour", 122 "SMP8634", 123 EUserAgent 124 }, 125 126 /* X-AV-Client-Info: av=5.0; cn="Sony Corporation"; mn="Blu-ray Disc Player"; mv="2.0" */ 127 /* X-AV-Client-Info: av=5.0; cn="Sony Corporation"; mn="BLU-RAY HOME THEATRE SYSTEM"; mv="2.0"; */ 128 /* Sony SMP-100 needs the same treatment as their BDP-S370 */ 129 /* X-AV-Client-Info: av=5.0; cn="Sony Corporation"; mn="Media Player"; mv="2.0" */ 130 { ESonyBDP, 131 FLAG_DLNA, 132 "Sony BDP", 133 "mv=\"2.0\"", 134 EXAVClientInfo 135 }, 136 137 /* User-Agent: Linux/2.6.31-1.0 UPnP/1.0 DLNADOC/1.50 INTEL_NMPR/2.0 LGE_DLNA_SDK/1.5.0 */ 138 { ELGDevice, 139 FLAG_DLNA | FLAG_CAPTION_RES, 140 "LG", 141 "LGE_DLNA_SDK", 142 EUserAgent 143 }, 144 145 /* X-AV-Client-Info: av=5.0; cn="Sony Corporation"; mn="BRAVIA KDL-40EX503"; mv="1.7"; */ 146 { ESonyBravia, 147 FLAG_DLNA, 148 "Sony Bravia", 149 "BRAVIA", 150 EXAVClientInfo 151 }, 152 153 /* X-AV-Client-Info: av=5.0; hn=""; cn="Sony Corporation"; mn="INTERNET TV NSX-40GT 1"; mv="0.1"; */ 154 { ESonyInternetTV, 155 FLAG_DLNA, 156 "Sony Internet TV", 157 "INTERNET TV", 158 EXAVClientInfo 159 }, 160 161 { ENetgearEVA2000, 162 FLAG_MS_PFS | FLAG_RESIZE_THUMBS, 163 "EVA2000", 164 "Verismo,", 165 EUserAgent 166 }, 167 168 { EDirecTV, 169 FLAG_RESIZE_THUMBS, 170 "DirecTV", 171 "DIRECTV ", 172 EUserAgent 173 }, 174 175 { EToshibaTV, 176 FLAG_DLNA, 177 "Toshiba TV", 178 "UPnP/1.0 DLNADOC/1.50 Intel_SDK_for_UPnP_devices/1.2", 179 EUserAgent 180 }, 181 182 { ERokuSoundBridge, 183 FLAG_MS_PFS | FLAG_AUDIO_ONLY | FLAG_MIME_WAV_WAV | FLAG_FORCE_SORT, 184 "Roku SoundBridge", 185 "Roku SoundBridge", 186 EModelName 187 }, 188 189 { EMarantzDMP, 190 FLAG_DLNA | FLAG_MIME_WAV_WAV, 191 "marantz DMP", 192 "marantz DMP", 193 EFriendlyNameSSDP 194 }, 195 196 { EMediaRoom, 197 FLAG_MS_PFS, 198 "MS MediaRoom", 199 "Microsoft-IPTV-Client", 200 EUserAgent 201 }, 202 203 { ELifeTab, 204 FLAG_MS_PFS, 205 "LIFETAB", 206 "LIFETAB", 207 EFriendlyName 208 }, 209 210 { EAsusOPlay, 211 FLAG_DLNA | FLAG_MIME_AVI_AVI | FLAG_CAPTION_RES, 212 "Asus OPlay Mini/Mini+", 213 "O!Play", 214 EUserAgent 215 }, 216 217 { EBubbleUPnP, 218 FLAG_CAPTION_RES, 219 "BubbleUPnP", 220 "BubbleUPnP", 221 EUserAgent 222 }, 223 224 { EStandardDLNA150, 225 FLAG_DLNA | FLAG_MIME_AVI_AVI, 226 "Generic DLNA 1.5", 227 "DLNADOC/1.50", 228 EUserAgent 229 }, 230 231 { EStandardUPnP, 232 0, 233 "Generic UPnP 1.0", 234 "UPnP/1.0", 235 EUserAgent 236 }, 237 238 { 0, 0, NULL, 0 } 239}; 240 241struct client_cache_s clients[CLIENT_CACHE_SLOTS]; 242 243struct client_cache_s * 244SearchClientCache(struct in_addr addr, int quiet) 245{ 246 int i; 247 248 for (i = 0; i < CLIENT_CACHE_SLOTS; i++) 249 { 250 if (clients[i].addr.s_addr == addr.s_addr) 251 { 252 /* Invalidate this client cache if it's older than 1 hour */ 253 if ((time(NULL) - clients[i].age) > 3600) 254 { 255 unsigned char mac[6]; 256 if (get_remote_mac(addr, mac) == 0 && 257 memcmp(mac, clients[i].mac, 6) == 0) 258 { 259 /* Same MAC as last time when we were able to identify the client, 260 * so extend the timeout by another hour. */ 261 clients[i].age = time(NULL); 262 } 263 else 264 { 265 memset(&clients[i], 0, sizeof(struct client_cache_s)); 266 return NULL; 267 } 268 } 269 if (!quiet) 270 DPRINTF(E_DEBUG, L_HTTP, "Client found in cache. [%s/entry %d]\n", 271 clients[i].type->name, i); 272 return &clients[i]; 273 } 274 } 275 276 return NULL; 277} 278 279struct client_cache_s * 280AddClientCache(struct in_addr addr, int type) 281{ 282 int i; 283 284 for (i = 0; i < CLIENT_CACHE_SLOTS; i++) 285 { 286 if (clients[i].addr.s_addr) 287 continue; 288 get_remote_mac(addr, clients[i].mac); 289 clients[i].addr = addr; 290 clients[i].type = &client_types[type]; 291 clients[i].age = time(NULL); 292 DPRINTF(E_DEBUG, L_HTTP, "Added client [%s/%s/%02X:%02X:%02X:%02X:%02X:%02X] to cache slot %d.\n", 293 client_types[type].name, inet_ntoa(clients[i].addr), 294 clients[i].mac[0], clients[i].mac[1], clients[i].mac[2], 295 clients[i].mac[3], clients[i].mac[4], clients[i].mac[5], i); 296 return &clients[i]; 297 } 298 299 return NULL; 300} 301 302