SIP Witch 1.9.15
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
cache.cpp
Go to the documentation of this file.
1 // Copyright (C) 2006-2014 David Sugar, Tycho Softworks.
2 // Copyright (C) 2015 Cherokees of Idaho.
3 //
4 // This program is free software; you can redistribute it and/or modify
5 // it under the terms of the GNU General Public License as published by
6 // the Free Software Foundation; either version 3 of the License, or
7 // (at your option) any later version.
8 //
9 // This program is distributed in the hope that it will be useful,
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the
12 // GNU General Public License for more details.
13 //
14 // You should have received a copy of the GNU General Public License
15 // along with this program. If not, see <http://www.gnu.org/licenses/>.
16 
17 #include <sipwitch-config.h>
18 #include <ucommon/ucommon.h>
19 #include <ucommon/export.h>
20 #include <sipwitch/cache.h>
21 #include <sipwitch/control.h>
22 #include <new>
23 
24 #define USER_KEY_SIZE 177
25 
26 namespace sipwitch {
27 
28 static mempager cache_heap(16384);
29 static LinkedObject *user_freelist = NULL;
30 static condlock_t user_lock;
31 static LinkedObject *user_keys[USER_KEY_SIZE];
32 
35 {
36  time(&created);
37 }
38 
40 Cache()
41 {
42 }
43 
44 void Cache::expire(LinkedObject **root, LinkedObject **freelist)
45 {
46  Cache *prior = NULL;
47  Cache *node = (Cache *)*root;
48  Cache *after;
49  time_t now;
50 
51  time(&now);
52 
53  while(node) {
54  after = (Cache *)node->Next;
55  if(node->expires && now > node->expires) {
56  if(!prior)
57  *root = after;
58  else
59  prior->Next = after;
60  node->enlist(freelist);
61  }
62  else
63  prior = node;
64  node = after;
65  }
66 }
67 
68 void cache::init(void)
69 {
70  memset(&user_keys, 0, sizeof(user_keys));
71 }
72 
73 void cache::cleanup(void)
74 {
75  for(unsigned i = 0; i < USER_KEY_SIZE; ++i) {
76  user_lock.modify();
77  expire(&user_keys[i], &user_freelist);
78  user_lock.commit();
79  }
80 }
81 
82 void cache::userdump(void)
83 {
84  FILE *fp = control::output("usercache");
85  char buffer[128];
86  time_t now;
87 
88  if(!fp) {
89  shell::log(shell::ERR, "%s\n",
90  _TEXT("usercache; cannot access file"));
91  return;
92  }
93 
94  for(unsigned i = 0; i < USER_KEY_SIZE; ++i) {
95  user_lock.access();
96  time(&now);
97  linked_pointer<UserCache> up = user_keys[i];
98  while(is(up)) {
99  if(!up->expires || up->expires > now) {
100  Socket::query((struct sockaddr *)(&up->address), buffer, sizeof(buffer));
101  if(up->expires)
102  fprintf(fp, "%s=%s; expires=%ld\n",
103  up->userid, buffer, (long)(up->expires - now));
104  else
105  fprintf(fp, "%s=%s\n", up->userid, buffer);
106  }
107  up.next();
108  }
109  user_lock.release();
110  }
111 
112  fclose(fp);
113 }
114 
116 {
117  assert(id != NULL && *id != 0);
118 
119  linked_pointer<UserCache> up;
120  unsigned path = NamedObject::keyindex(id, USER_KEY_SIZE);
121  up = user_keys[path];
122  while(up) {
123  if(eq(up->userid, id))
124  break;
125  up.next();
126  }
127  return *up;
128 }
129 
130 UserCache *UserCache::find(const char *id)
131 {
132  time_t now;
133  time(&now);
134 
135  if(strchr(id, '@'))
136  return NULL;
137 
138  user_lock.access();
139  UserCache *cp = request(id);
140  if(cp) {
141  if(!cp->expires || cp->expires > now)
142  return cp;
143  }
144  user_lock.release();
145  return NULL;
146 }
147 
149 {
150  LinkedObject::release();
151 }
152 
154 {
155  if(entry)
156  user_lock.release();
157 }
158 
159 void UserCache::add(const char *id, struct sockaddr *addr, time_t create, unsigned expire)
160 {
161  assert(id != NULL && *id != 0);
162 
163  if(strchr(id, '@'))
164  return;
165 
166  unsigned path = NamedObject::keyindex(id, USER_KEY_SIZE);
167 
168  user_lock.modify();
169  UserCache *cp = request(id);
170  if(cp) {
171  // only update if not trumped by existing entry...
172  if(create >= cp->created)
173  goto update;
174  goto release;
175  }
176 
177  if(user_freelist) {
178  cp = (UserCache *)user_freelist;
179  user_freelist = cp->Next;
180  }
181  else {
182  void *mp = cache_heap.alloc(sizeof(UserCache));
183  cp = new(mp) UserCache;
184  }
185 
186  cp->enlist(&user_keys[path]);
187  String::set(cp->userid, sizeof(cp->userid), id);
188 
189 update:
190  cp->created = create;
191  if(expire) {
192  time(&cp->expires);
193  cp->expires += expire;
194  }
195  else
196  cp->expires = 0;
197  cp->set(addr);
198 
199 release:
200  user_lock.commit();
201 }
202 
203 } // end namespace
time_t expires
Definition: cache.h:65
static UserCache * request(const char *id)
Definition: cache.cpp:115
static void userdump(void)
Definition: cache.cpp:82
static void expire(LinkedObject **list, LinkedObject **free)
Definition: cache.cpp:44
static void cleanup(void)
Definition: cache.cpp:73
static UserCache * find(const char *id)
Find user record.
Definition: cache.cpp:130
static void init(void)
Definition: cache.cpp:68
void release(void)
Definition: cache.cpp:148
URI cache for tags, local, and remote id's.
Definition: cache.h:56
static bool static FILE * output(const char *id)
Used to open an output session for returning control data.
Definition: control.cpp:380
time_t created
Definition: cache.h:64
char userid[32]
Definition: cache.h:95
#define USER_KEY_SIZE
Definition: cache.cpp:24
Manage control interface.
static void add(const char *id, struct sockaddr *addr, time_t create, unsigned expire=130)
Add or refresh user in cache.
Definition: cache.cpp:159
User caches may be used to contact nearby users in multicast registries.
Definition: cache.h:84
void set(struct sockaddr *addr)
Definition: cache.h:98