]>
Commit | Line | Data |
---|---|---|
84563ebd | 1 | /* Keeps track of current "dangling" auths. |
2 | * | |
3 | * Every entry here corresponds to a user who has an open session in the | |
4 | * session table, but we cannot be sure that the user has actually gone. | |
5 | * This means either (a) their server has split off or (b) we restarted and | |
6 | * found a dangling entry in the session table. | |
7 | * | |
8 | * Entries leave when either (a) the user comes back (the entry is dropped), | |
9 | * or (b) the server the user was on relinks without them, in which case we | |
10 | * close off their session. | |
11 | */ | |
12 | ||
13 | #include "authtracker.h" | |
14 | #include "../../core/nsmalloc.h" | |
15 | #include "../../server/server.h" | |
16 | #include "../../irc/irc_config.h" | |
17 | ||
18 | #include <time.h> | |
19 | ||
20 | #define DANGLING_HASHSIZE 500 | |
21 | #define dangling_hash(x) ((x)%DANGLING_HASHSIZE) | |
22 | ||
23 | #define ALLOCUNIT 100 | |
24 | ||
25 | struct dangling_entry { | |
26 | unsigned int numeric; | |
27 | unsigned long userid; | |
28 | time_t authts; | |
29 | time_t losttime; | |
30 | int reason; /* AT_NETSPLIT or AT_RESTART */ | |
31 | struct dangling_entry *next; | |
32 | }; | |
33 | ||
34 | struct dangling_server { | |
35 | struct dangling_entry *de[DANGLING_HASHSIZE]; | |
36 | }; | |
37 | ||
38 | struct dangling_server *ds[MAXSERVERS]; | |
39 | struct dangling_entry *free_des; | |
40 | ||
41 | static struct dangling_entry *get_de() { | |
42 | struct dangling_entry *dep; | |
43 | int i; | |
44 | ||
45 | if (free_des == NULL) { | |
46 | free_des = (struct dangling_entry *)nsmalloc(POOL_AUTHTRACKER, ALLOCUNIT * sizeof(struct dangling_entry)); | |
47 | for (i=0;i<(ALLOCUNIT-1);i++) { | |
48 | free_des[i].next= &(free_des[i+1]); | |
49 | } | |
50 | free_des[ALLOCUNIT-1].next=NULL; | |
51 | } | |
52 | ||
53 | dep=free_des; | |
54 | free_des=dep->next; | |
55 | ||
56 | return dep; | |
57 | } | |
58 | ||
59 | static void free_de(struct dangling_entry *dep) { | |
60 | dep->next=free_des; | |
61 | free_des=dep; | |
62 | } | |
63 | ||
64 | void at_lostnick(unsigned int numeric, unsigned long userid, time_t accountts, time_t losttime, int reason) { | |
65 | unsigned int server=homeserver(numeric); | |
66 | unsigned int i; | |
67 | struct dangling_entry *dep; | |
68 | unsigned int thehash=dangling_hash(numeric); | |
69 | ||
70 | /* If their server doesn't have an entry, make one. */ | |
71 | if (!ds[server]) { | |
72 | ds[server]=nsmalloc(POOL_AUTHTRACKER, sizeof(struct dangling_server)); | |
73 | for (i=0;i<DANGLING_HASHSIZE;i++) | |
74 | ds[server]->de[i]=NULL; | |
75 | } | |
76 | ||
77 | /* Now make an entry */ | |
78 | dep=get_de(); | |
79 | dep->numeric=numeric; | |
80 | dep->userid=userid; | |
81 | dep->authts=accountts; | |
82 | dep->losttime=losttime; | |
83 | dep->reason=reason; | |
84 | dep->next=ds[server]->de[thehash]; | |
85 | ds[server]->de[thehash]=dep; | |
86 | } | |
87 | ||
88 | /* Removes a returning user from the "dangling" tables. Return 1 if we found it, 0 otherwise. */ | |
89 | int at_foundnick(unsigned int numeric, unsigned long userid, time_t accountts) { | |
90 | unsigned int server=homeserver(numeric); | |
91 | struct dangling_entry *dep, **deh; | |
92 | unsigned int thehash=dangling_hash(numeric); | |
93 | ||
94 | /* If we've not got an entry for their server we certainly won't for them. */ | |
95 | if (!ds[server]) | |
96 | return 0; | |
97 | ||
98 | for (deh=&(ds[server]->de[thehash]); *deh; deh=&((*deh)->next)) { | |
99 | dep=*deh; | |
100 | if ((dep->numeric == numeric) && (dep->userid==userid) && (dep->authts==accountts)) { | |
101 | /* Got it */ | |
102 | *deh=dep->next; | |
103 | free_de(dep); | |
104 | return 1; | |
105 | } | |
106 | } | |
107 | ||
108 | /* Dropped through - didn't find it */ | |
109 | return 0; | |
110 | } | |
111 | ||
112 | /* When a server is back (fully linked), any remaining dangling users on that server are definately gone. */ | |
113 | void at_serverback(unsigned int server) { | |
114 | int i; | |
115 | struct dangling_entry *dep, *ndep; | |
116 | ||
117 | if (!ds[server]) | |
118 | return; | |
119 | ||
120 | for (i=0;i<DANGLING_HASHSIZE;i++) { | |
121 | for (dep=ds[server]->de[i];dep;dep=ndep) { | |
122 | ndep=dep->next; | |
123 | ||
124 | at_logquit(dep->userid, dep->authts, time(NULL), (dep->reason==AT_NETSPLIT)? "(netsplit)" : "(restart)"); | |
125 | free_de(dep); | |
126 | } | |
127 | } | |
128 | ||
129 | nsfree(POOL_AUTHTRACKER, ds[server]); | |
130 | ds[server]=NULL; | |
131 | } | |
132 | ||
133 | void at_flushghosts() { | |
134 | int i; | |
135 | ||
136 | for (i=0;i<MAXSERVERS;i++) { | |
137 | if (serverlist[i].linkstate == LS_LINKED) | |
138 | at_serverback(i); | |
139 | } | |
140 | } |