Adjust copyright for 2010
[bcusdk.git] / eibd / libserver / groupcache.cpp
blob2b1f00ae7c8cb52a6c538eb0f67afd3f0185b7ad
1 /*
2 EIBD eib bus access and management daemon
3 Copyright (C) 2005-2010 Martin Koegler <mkoegler@auto.tuwien.ac.at>
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 2 of the License, or
8 (at your option) any later version.
10 This program 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.
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
20 #include "groupcache.h"
21 #include "tpdu.h"
22 #include "apdu.h"
24 GroupCache::GroupCache (Layer3 * l3, Trace * t)
26 TRACEPRINTF (t, 4, this, "GroupCacheInit");
27 this->t = t;
28 this->layer3 = l3;
29 this->enable = 0;
30 pth_mutex_init (&mutex);
31 pth_cond_init (&cond);
34 GroupCache::~GroupCache ()
36 TRACEPRINTF (t, 4, this, "GroupCacheDestroy");
37 if (enable)
38 layer3->deregisterGroupCallBack (this, 0);
39 Clear ();
42 GroupCacheEntry *
43 GroupCache::find (eibaddr_t dst)
45 int l = 0, r = cache () - 1;
46 while (l <= r)
48 int p = (l + r) / 2;
49 if (cache[p]->dst == dst)
50 return cache[p];
51 if (dst > cache[p]->dst)
52 l = p + 1;
53 else
54 r = p - 1;
56 return 0;
59 void
60 GroupCache::remove (eibaddr_t addr)
62 TRACEPRINTF (t, 4, this, "GroupCacheRemove %d/%d/%d", (addr >> 11) & 0x1f,
63 (addr >> 8) & 0x07, (addr) & 0xff);
65 int l = 0, r = cache () - 1;
66 while (l <= r)
68 int p = (l + r) / 2;
69 if (cache[p]->dst == addr)
71 delete cache[p];
72 cache.deletepart (p, 1);
73 return;
75 if (addr > cache[p]->dst)
76 l = p + 1;
77 else
78 r = p - 1;
80 return;
83 void
84 GroupCache::add (GroupCacheEntry * entry)
86 unsigned p;
87 cache.resize (cache () + 1);
88 p = cache () - 1;
89 while (p > 0 && cache[p - 1]->dst > entry->dst)
91 cache[p] = cache[p - 1];
92 p--;
94 cache[p] = entry;
98 void
99 GroupCache::Get_L_Data (L_Data_PDU * l)
101 GroupCacheEntry *c;
102 if (enable)
104 TPDU *t = TPDU::fromPacket (l->data);
105 if (t->getType () == T_DATA_XXX_REQ)
107 T_DATA_XXX_REQ_PDU *t1 = (T_DATA_XXX_REQ_PDU *) t;
108 if (t1->data () >= 2 && !(t1->data[0] & 0x3) &&
109 ((t1->data[1] & 0xC0) == 0x40 || (t1->data[1] & 0xC0) == 0x80))
111 c = find (l->dest);
112 if (c)
114 c->data = t1->data;
115 c->src = l->source;
116 c->dst = l->dest;
117 c->recvtime = time (0);
118 pth_cond_notify (&cond, 1);
120 else
122 c = new GroupCacheEntry;
123 c->data = t1->data;
124 c->src = l->source;
125 c->dst = l->dest;
126 c->recvtime = time (0);
127 add (c);
128 pth_cond_notify (&cond, 1);
132 delete t;
134 delete l;
137 bool
138 GroupCache::Start ()
140 TRACEPRINTF (t, 4, this, "GroupCacheEnable");
141 if (!enable)
142 if (!layer3->registerGroupCallBack (this, 0))
143 return false;
144 enable = 1;
145 return true;
148 void
149 GroupCache::Clear ()
151 int i;
152 TRACEPRINTF (t, 4, this, "GroupCacheClear");
153 for (i = 0; i < cache (); i++)
154 delete cache[i];
155 cache.resize (0);
158 void
159 GroupCache::Stop ()
161 Clear ();
162 TRACEPRINTF (t, 4, this, "GroupCacheStop");
163 if (enable)
164 layer3->deregisterGroupCallBack (this, 0);
165 enable = 0;
168 GroupCacheEntry
169 GroupCache::Read (eibaddr_t addr, unsigned Timeout, uint16_t age)
171 TRACEPRINTF (t, 4, this, "GroupCacheRead %d/%d/%d %d %d",
172 (addr >> 11) & 0x1f, (addr >> 8) & 0x07, (addr) & 0xff,
173 Timeout, age);
174 bool rm = false;
175 GroupCacheEntry *c;
176 if (!enable)
178 GroupCacheEntry f;
179 f.src = 0;
180 f.dst = 0;
181 TRACEPRINTF (t, 4, this, "GroupCache not enabled");
182 return f;
185 c = find (addr);
186 if (c && age && c->recvtime + age < time (0))
187 rm = true;
189 if (c && !rm)
191 TRACEPRINTF (t, 4, this, "GroupCache found: %d.%d.%d",
192 (c->src >> 12) & 0xf, (c->src >> 8) & 0xf,
193 (c->src) & 0xff);
194 return *c;
197 if (!Timeout)
199 GroupCacheEntry f;
200 f.src = 0;
201 f.dst = addr;
202 TRACEPRINTF (t, 4, this, "GroupCache no entry");
203 return f;
206 A_GroupValue_Read_PDU apdu;
207 T_DATA_XXX_REQ_PDU tpdu;
208 L_Data_PDU *l;
209 pth_event_t timeout = pth_event (PTH_EVENT_RTIME, pth_time (Timeout, 0));;
211 tpdu.data = apdu.ToPacket ();
212 l = new L_Data_PDU;
213 l->data = tpdu.ToPacket ();
214 l->source = 0;
215 l->dest = addr;
216 l->AddrType = GroupAddress;
217 layer3->send_L_Data (l);
221 c = find (addr);
222 rm = false;
223 if (c && age && c->recvtime + age < time (0))
224 rm = true;
226 if (c && !rm)
228 TRACEPRINTF (t, 4, this, "GroupCache found: %d.%d.%d",
229 (c->src >> 12) & 0xf, (c->src >> 8) & 0xf,
230 (c->src) & 0xff);
231 pth_event_free (timeout, PTH_FREE_THIS);
232 return *c;
235 if (pth_event_status (timeout) == PTH_STATUS_OCCURRED && c)
237 GroupCacheEntry gc;
238 gc.src = 0;
239 gc.dst = addr;
240 TRACEPRINTF (t, 4, this, "GroupCache reread timeout");
241 pth_event_free (timeout, PTH_FREE_THIS);
242 return gc;
245 if (pth_event_status (timeout) == PTH_STATUS_OCCURRED)
247 c = new GroupCacheEntry;
248 c->src = 0;
249 c->dst = addr;
250 c->recvtime = time (0);
251 add (c);
252 TRACEPRINTF (t, 4, this, "GroupCache timeout");
253 pth_event_free (timeout, PTH_FREE_THIS);
254 return *c;
257 pth_mutex_acquire (&mutex, 0, 0);
258 pth_cond_await (&cond, &mutex, timeout);
259 pth_mutex_release (&mutex);
261 while (1);