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