1 /* $Id: wip.c 8709 2009-11-06 21:47:11Z iulius $
2 **
3 ** Routines for keeping track of incoming articles, articles that haven't
4 ** acked from a duplex channel feed, and history caching.
5 **
6 ** WIP stands for work-in-progress
7 */
8
9 #include "config.h"
10 #include "clibrary.h"
11
12 #include "inn/innconf.h"
13 #include "innd.h"
14
15 #define WIPTABLESIZE 1024
16 #define WIP_ARTMAX 300 /* innfeed default max send time */
17
18 static WIP *WIPtable[WIPTABLESIZE]; /* Top level of the WIP hash table */
19
20 void
WIPsetup(void)21 WIPsetup(void)
22 {
23 memset(WIPtable, '\0', sizeof(WIPtable));
24 }
25
26 /* Add a new entry into the table. It is the appilications responsiblity to
27 to call WIPinprogress or WIPbyid first. */
28 WIP *
WIPnew(const char * messageid,CHANNEL * cp)29 WIPnew(const char *messageid, CHANNEL *cp)
30 {
31 HASH hash;
32 unsigned long bucket;
33 WIP *new;
34
35 hash = Hash(messageid, strlen(messageid));
36 memcpy(&bucket, &hash,
37 sizeof(bucket) < sizeof(hash) ? sizeof(bucket) : sizeof(hash));
38 bucket = bucket % WIPTABLESIZE;
39
40 new = xmalloc(sizeof(WIP));
41 new->MessageID = hash;
42 new->Timestamp = Now.tv_sec;
43 new->Chan = cp;
44 /* Link the new entry into the list */
45 new->Next = WIPtable[bucket];
46 WIPtable[bucket] = new;
47 return new;
48 }
49
50 void
WIPprecomfree(CHANNEL * cp)51 WIPprecomfree(CHANNEL *cp)
52 {
53 WIP *cur;
54 int i;
55 if (cp == NULL)
56 return;
57
58 for (i = 0 ; i < PRECOMMITCACHESIZE ; i++) {
59 cur = cp->PrecommitWIP[i];
60 if (cur != (WIP *)NULL) {
61 WIPfree(cur);
62 }
63 }
64 }
65
66 void
WIPfree(WIP * wp)67 WIPfree(WIP *wp)
68 {
69 unsigned long bucket;
70 WIP *cur;
71 WIP *prev = NULL;
72 int i;
73 /* This is good error checking, but also allows us to
74 WIPfree(WIPbymessageid(id))
75 without having to check if id exists first */
76 if (wp == NULL)
77 return;
78
79 memcpy(&bucket, &wp->MessageID,
80 sizeof(bucket) < sizeof(HASH) ? sizeof(bucket) : sizeof(HASH));
81 bucket = bucket % WIPTABLESIZE;
82
83 for (i = 0 ; i < PRECOMMITCACHESIZE ; i++) {
84 if (wp->Chan->PrecommitWIP[i] == wp) {
85 wp->Chan->PrecommitWIP[i] = (WIP *)NULL;
86 break;
87 }
88 }
89 for (cur = WIPtable[bucket]; (cur != NULL) && (cur != wp); prev = cur, cur = cur->Next);
90
91 if (cur == NULL)
92 return;
93
94 if (prev == NULL)
95 WIPtable[bucket] = cur->Next;
96 else
97 prev->Next = cur->Next;
98
99 /* unlink the entry and free the memory */
100 free(wp);
101 }
102
103 /* Check if the given messageid is being transfered on another channel. If
104 Add is true then add the given message-id to the current channel */
105 bool
WIPinprogress(const char * msgid,CHANNEL * cp,bool Precommit)106 WIPinprogress(const char *msgid, CHANNEL *cp, bool Precommit)
107 {
108 WIP *wp;
109 unsigned long i;
110
111 if ((wp = WIPbyid(msgid)) != NULL) {
112 if(wp->Chan->ArtBeg == 0)
113 i = 0;
114 else {
115 i = wp->Chan->ArtMax;
116 if(i > WIP_ARTMAX)
117 i = WIP_ARTMAX;
118 }
119
120 if ((Now.tv_sec - wp->Timestamp) < (time_t) (i + innconf->wipcheck))
121 return true;
122 if ((Now.tv_sec - wp->Timestamp) > (time_t) (i + innconf->wipexpire)) {
123 for (i = 0 ; i < PRECOMMITCACHESIZE ; i++) {
124 if (wp->Chan->PrecommitWIP[i] == wp) {
125 wp->Chan->PrecommitWIP[i] = (WIP *)NULL;
126 break;
127 }
128 }
129 WIPfree(wp);
130 WIPinprogress(msgid, cp, Precommit);
131 return false;
132 }
133 if (wp->Chan == cp)
134 return true;
135 return false;
136 }
137 wp = WIPnew(msgid, cp);
138 if (Precommit) {
139 if (cp->PrecommitiCachenext == PRECOMMITCACHESIZE)
140 cp->PrecommitiCachenext = 0;
141 if (cp->PrecommitWIP[cp->PrecommitiCachenext])
142 WIPfree(cp->PrecommitWIP[cp->PrecommitiCachenext]);
143 cp->PrecommitWIP[cp->PrecommitiCachenext++] = wp;
144 } else {
145 WIPfree(WIPbyhash(cp->CurrentMessageIDHash));
146 cp->CurrentMessageIDHash = wp->MessageID;
147 }
148 return false;
149 }
150
151 WIP *
WIPbyid(const char * messageid)152 WIPbyid(const char *messageid)
153 {
154 HASH hash;
155 unsigned long bucket;
156 WIP *wp;
157
158 hash = Hash(messageid, strlen(messageid));
159 memcpy(&bucket, &hash,
160 sizeof(bucket) < sizeof(hash) ? sizeof(bucket) : sizeof(hash));
161 bucket = bucket % WIPTABLESIZE;
162
163 /* Traverse the list until we find a match or find the head again */
164 for (wp = WIPtable[bucket]; wp != NULL; wp = wp->Next)
165 if (!memcmp(&hash, &wp->MessageID, sizeof(HASH)))
166 return wp;
167
168 return NULL;
169 }
170
171 WIP *
WIPbyhash(const HASH hash)172 WIPbyhash(const HASH hash)
173 {
174 unsigned long bucket;
175 WIP *wp;
176
177 memcpy(&bucket, &hash,
178 sizeof(bucket) < sizeof(hash) ? sizeof(bucket) : sizeof(hash));
179 bucket = bucket % WIPTABLESIZE;
180
181 /* Traverse the list until we find a match or find the head again */
182 for (wp = WIPtable[bucket]; wp != NULL; wp = wp->Next)
183 if (!memcmp(&hash, &wp->MessageID, sizeof(HASH)))
184 return wp;
185
186 return NULL;
187 }
188