1 #ifndef _RegisterCache_h_ 2 #define _RegisterCache_h_ 3 4 #include "singleton.h" 5 #include "hash_table.h" 6 #include "atomic_types.h" 7 8 #include "AmSipMsg.h" 9 #include "AmUriParser.h" 10 #include "AmAppTimer.h" 11 12 #include <string> 13 #include <map> 14 #include <memory> 15 using std::string; 16 using std::map; 17 using std::unique_ptr; 18 19 #define REG_CACHE_TABLE_POWER 10 20 #define REG_CACHE_TABLE_ENTRIES (1<<REG_CACHE_TABLE_POWER) 21 22 #define DEFAULT_REG_EXPIRES 3600 23 24 /* 25 * Register cache: 26 * --------------- 27 * Data model: 28 * - canonical AoR <--1-to-n--> contacts 29 * - alias <--1-to-1--> contact 30 */ 31 32 struct RegBinding 33 { 34 // Absolute timestamp representing 35 // the expiration timer at the 36 // registrar side 37 long int reg_expire; 38 39 // unique-id used as contact user toward the registrar 40 string alias; 41 RegBindingRegBinding42 RegBinding() 43 : reg_expire(0) 44 {} 45 }; 46 47 // Contact-URI/Public-IP -> RegBinding 48 typedef map<string,RegBinding*> AorEntry; 49 50 struct AliasEntry 51 : public DirectAppTimer 52 { 53 string aor; 54 string contact_uri; 55 string alias; 56 57 // saved state for NAT handling 58 string source_ip; 59 unsigned short source_port; 60 string trsp; 61 62 // sticky interface 63 unsigned short local_if; 64 65 // User-Agent 66 string remote_ua; 67 68 // Absolute timestamp representing 69 // the expiration timer at the 70 // registered UA side 71 long int ua_expire; 72 AliasEntryAliasEntry73 AliasEntry() 74 : source_port(0), local_if(0), ua_expire(0) 75 {} 76 77 // from DirectAppTimer 78 void fire(); 79 }; 80 81 struct RegCacheStorageHandler 82 { onDeleteRegCacheStorageHandler83 virtual void onDelete(const string& aor, const string& uri, 84 const string& alias) {} 85 onUpdateRegCacheStorageHandler86 virtual void onUpdate(const string& canon_aor, const string& alias, 87 long int expires, const AliasEntry& alias_update) {} 88 onUpdateRegCacheStorageHandler89 virtual void onUpdate(const string& alias, long int ua_expires) {} 90 }; 91 92 /** 93 * Hash-table bucket: 94 * AoR -> AorEntry 95 */ 96 class AorBucket 97 : public ht_map_bucket<string,AorEntry> 98 { 99 public: AorBucket(unsigned long id)100 AorBucket(unsigned long id) 101 : ht_map_bucket<string,AorEntry>(id) 102 {} 103 104 /** 105 * Match and retrieve the cache entry associated with the AOR passed. 106 * aor: canonicalized AOR 107 */ 108 AorEntry* get(const string& aor); 109 110 /* Maintenance stuff */ 111 112 void gbc(RegCacheStorageHandler* h, long int now, list<string>& alias_list); 113 void dump_elmt(const string& aor, const AorEntry* p_aor_entry) const; 114 }; 115 116 /** 117 * Hash-table bucket: 118 * Alias -> Contact-URI 119 */ 120 class AliasBucket 121 : public ht_map_bucket<string,AliasEntry> 122 { 123 public: AliasBucket(unsigned long int id)124 AliasBucket(unsigned long int id) 125 : ht_map_bucket<string,AliasEntry>(id) 126 {} 127 128 AliasEntry* getContact(const string& alias); 129 130 void dump_elmt(const string& alias, const AliasEntry* ae) const; 131 }; 132 133 class ContactBucket 134 : public ht_map_bucket<string,string> 135 { 136 typedef ht_map_bucket<string,string> Bucket; 137 insert(const string & k,string * v)138 bool insert(const string& k, string* v) { 139 return Bucket::insert(k,v); 140 } 141 remove(const string & k)142 bool remove(const string& k) { 143 return Bucket::remove(k); 144 } 145 146 public: ContactBucket(unsigned long int id)147 ContactBucket(unsigned long int id) 148 : ht_map_bucket<string,string>(id) 149 {} 150 151 void insert(const string& contact_uri, const string& remote_ip, 152 unsigned short remote_port, const string& alias); 153 154 string getAlias(const string& contact_uri, const string& remote_ip, 155 unsigned short remote_port); 156 157 void remove(const string& contact_uri, const string& remote_ip, 158 unsigned short remote_port); 159 160 void dump_elmt(const string& key, const string* alias) const; 161 }; 162 163 /** 164 * Registrar/Reg-Caching 165 * parsing/processing context 166 */ 167 struct RegisterCacheCtx 168 : public AmObject 169 { 170 string from_aor; 171 bool aor_parsed; 172 173 vector<AmUriParser> contacts; 174 bool contacts_parsed; 175 176 unsigned int requested_expires; 177 bool expires_parsed; 178 179 unsigned int min_reg_expires; 180 unsigned int max_ua_expires; 181 RegisterCacheCtxRegisterCacheCtx182 RegisterCacheCtx() 183 : aor_parsed(false), 184 contacts_parsed(false), 185 requested_expires(DEFAULT_REG_EXPIRES), 186 expires_parsed(false), 187 min_reg_expires(0), 188 max_ua_expires(0) 189 {} 190 }; 191 192 class _RegisterCache 193 : public AmThread 194 { 195 hash_table<AorBucket> reg_cache_ht; 196 hash_table<AliasBucket> id_idx; 197 hash_table<ContactBucket> contact_idx; 198 199 unique_ptr<RegCacheStorageHandler> storage_handler; 200 201 unsigned int gbc_bucket_id; 202 203 AmSharedVar<bool> running; 204 205 // stats 206 atomic_int active_regs; 207 208 void gbc(unsigned int bucket_id); 209 void removeAlias(const string& alias, bool generate_event); 210 211 protected: 212 _RegisterCache(); 213 ~_RegisterCache(); 214 dispose()215 void dispose() { stop(); } 216 217 /* AmThread interface */ 218 void run(); 219 void on_stop(); 220 221 /** 222 * Returns the bucket associated with the passed contact-uri 223 * aor: canonicalized AOR 224 */ 225 AorBucket* getAorBucket(const string& aor); 226 227 /** 228 * Returns the bucket associated with the alias given 229 * alias: Contact-user 230 */ 231 AliasBucket* getAliasBucket(const string& alias); 232 233 /** 234 * Returns the bucket associated with the contact-URI given 235 */ 236 ContactBucket* getContactBucket(const string& contact_uri, 237 const string& remote_ip, 238 unsigned short remote_port); 239 240 int parseAoR(RegisterCacheCtx& ctx, const AmSipRequest& req, msg_logger *logger); 241 int parseContacts(RegisterCacheCtx& ctx, const AmSipRequest& req, msg_logger *logger); 242 int parseExpires(RegisterCacheCtx& ctx, const AmSipRequest& req, msg_logger *logger); 243 244 void setAliasUATimer(AliasEntry* alias_e); 245 void removeAliasUATimer(AliasEntry* alias_e); 246 247 public: 248 static string canonicalize_aor(const string& aor); 249 static string compute_alias_hash(const string& aor, const string& contact_uri, 250 const string& public_ip); 251 setStorageHandler(RegCacheStorageHandler * h)252 void setStorageHandler(RegCacheStorageHandler* h) { storage_handler.reset(h); } 253 254 /** 255 * Match, retrieve the contact cache entry associated with the URI passed, 256 * and return the alias found in the cache entry. 257 * 258 * Note: this function locks and unlocks the contact cache bucket. 259 * 260 * aor: canonical Address-of-Record 261 * uri: Contact-URI 262 */ 263 bool getAlias(const string& aor, const string& uri, 264 const string& public_ip, RegBinding& out_binding); 265 266 /** 267 * Update contact cache entry and alias map entries. 268 * 269 * Note: this function locks and unlocks 270 * the contact cache bucket and 271 * the alias map bucket. 272 * 273 * aor: canonical Address-of-Record 274 * uri: Contact-URI 275 * alias: 276 */ 277 void update(const string& alias, long int reg_expires, 278 const AliasEntry& alias_update); 279 280 void update(long int reg_expires, const AliasEntry& alias_update); 281 282 bool updateAliasExpires(const string& alias, long int ua_expires); 283 284 /** 285 * Remove contact cache entry and alias map entries. 286 * 287 * Note: this function locks and unlocks 288 * the contact cache bucket and 289 * the alias map bucket. 290 * 291 * aor: canonical Address-of-Record 292 * uri: Contact-URI 293 * alias: 294 */ 295 void remove(const string& aor, const string& uri, 296 const string& alias); 297 298 void remove(const string& aor); 299 300 /** 301 * Retrieve an alias map containing all entries related 302 * to a particular AOR. This is needed to support REGISTER 303 * with '*' contact. 304 * 305 * Note: this function locks and unlocks 306 * the contact cache bucket. 307 * 308 * aor: canonical Address-of-Record 309 * alias_map: alias -> contact 310 */ 311 bool getAorAliasMap(const string& aor, map<string,string>& alias_map); 312 313 /** 314 * Retrieve the alias entry related to the given alias 315 */ 316 bool findAliasEntry(const string& alias, AliasEntry& alias_entry); 317 318 /** 319 * Retrieve the alias entry related to the given contact-URI, remote-IP & port 320 */ 321 bool findAEByContact(const string& contact_uri, const string& remote_ip, 322 unsigned short remote_port, AliasEntry& ae); 323 324 /** 325 * Throttle REGISTER requests 326 * 327 * Returns false if REGISTER should be forwarded: 328 * - if registrar binding should be renewed. 329 * - if source IP or port do not match the saved IP & port. 330 * - if the request unregisters any contact. 331 * - if request is not a REGISTER 332 */ 333 bool throttleRegister(RegisterCacheCtx& ctx, 334 const AmSipRequest& req, 335 msg_logger *logger = NULL); 336 337 /** 338 * Save a single REGISTER contact into cache 339 * 340 * Returns false if failed: 341 * - if request is not a REGISTER. 342 * - more than one contact should be (un)registered. 343 * 344 * If true has been returned, the request has already 345 * been replied with either an error or 200 (w/ contact). 346 * 347 * Note: this function also handles binding query. 348 * (REGISTER w/o contacts) 349 */ 350 bool saveSingleContact(RegisterCacheCtx& ctx, 351 const AmSipRequest& req, 352 msg_logger *logger = NULL); 353 354 /** 355 * Statistics 356 */ getActiveRegs()357 unsigned int getActiveRegs() { return active_regs.get(); } 358 }; 359 360 typedef singleton<_RegisterCache> RegisterCache; 361 362 #endif 363