Peer organizations now parsed and added to peer table.
[trust_router.git] / trp / trp_ptable.c
1 #include <time.h>
2 #include <talloc.h>
3
4 #include <trust_router/tr_name.h>
5 #include <trp_internal.h>
6 #include <tr_gss.h>
7 #include <trp_ptable.h>
8 #include <tr_debug.h>
9
10 static int trp_peer_destructor(void *object)
11 {
12   TRP_PEER *peer=talloc_get_type_abort(object, TRP_PEER);
13   if (peer->servicename!=NULL)
14     tr_free_name(peer->servicename);
15   return 0;
16 }
17 TRP_PEER *trp_peer_new(TALLOC_CTX *memctx)
18 {
19   TRP_PEER *peer=talloc(memctx, TRP_PEER);
20   if (peer!=NULL) {
21     peer->next=NULL;
22     peer->server=NULL;
23     peer->servicename=NULL;
24     peer->gss_names=NULL;
25     peer->port=0;
26     peer->linkcost=TRP_LINKCOST_DEFAULT;
27     peer->last_conn_attempt=(struct timespec){0,0};
28     peer->outgoing_status=PEER_DISCONNECTED;
29     peer->incoming_status=PEER_DISCONNECTED;
30     peer->conn_status_cb=NULL;
31     peer->conn_status_cookie=NULL;
32     talloc_set_destructor((void *)peer, trp_peer_destructor);
33   }
34   return peer;
35 }
36
37 void trp_peer_free(TRP_PEER *peer)
38 {
39   talloc_free(peer);
40 }
41
42 static TRP_PEER *trp_peer_tail(TRP_PEER *peer)
43 {
44   while (peer->next!=NULL) {
45     peer=peer->next;
46   }
47   return peer;
48 }
49
50
51 /* Get a name that identifies this peer for display to the user, etc. 
52  * Do not modify or free the label. */
53 TR_NAME *trp_peer_get_label(TRP_PEER *peer)
54 {
55   TR_GSS_NAMES_ITER *iter=tr_gss_names_iter_new(NULL);
56   TR_NAME *name=NULL;
57
58   /* for now, use the first gss name */
59   if (iter!=NULL) {
60     name=tr_gss_names_iter_first(iter, peer->gss_names);
61     talloc_free(iter);
62   }
63   return name;
64 }
65
66 /* Get a name that identifies this peer for display to the user, etc. 
67  * Makes a copy, caller is responsible for freeing.  */
68 TR_NAME *trp_peer_dup_label(TRP_PEER *peer)
69 {
70   return tr_dup_name(trp_peer_get_label(peer));;
71 }
72
73 char *trp_peer_get_server(TRP_PEER *peer)
74 {
75   return peer->server;
76 }
77
78 static void trp_peer_set_servicename(TRP_PEER *peer, const char *server)
79 {
80   char *name=NULL;
81   if (peer->servicename !=NULL)
82     tr_free_name(peer->servicename);
83
84   if (server!=NULL)
85     name=talloc_asprintf(NULL, "trustrouter/%s", server);
86
87   if (name!=NULL) {
88     peer->servicename=tr_new_name(name);
89     talloc_free(name);
90   } else {
91     peer->servicename=NULL;
92   }
93 }
94
95 /* copies input; on error, peer->servicename will be null */
96 void trp_peer_set_server(TRP_PEER *peer, const char *server)
97 {
98   peer->server=talloc_strdup(peer, server); /* will be null on error */
99   trp_peer_set_servicename(peer, server);
100 }
101
102 void trp_peer_add_gss_name(TRP_PEER *peer, TR_NAME *gss_name)
103 {
104   if (peer->gss_names==NULL)
105     trp_peer_set_gss_names(peer, tr_gss_names_new(peer));
106   tr_gss_names_add(peer->gss_names, gss_name);
107 }
108
109 void trp_peer_set_gss_names(TRP_PEER *peer, TR_GSS_NAMES *gss_names)
110 {
111   if (peer->gss_names!=NULL)
112     talloc_free(peer->gss_names);
113
114   peer->gss_names=gss_names;
115   talloc_steal(peer, gss_names);
116 }
117
118 /* get the peer gss_names, caller must not free the result */
119 TR_GSS_NAMES *trp_peer_get_gss_names(TRP_PEER *peer)
120 {
121   return peer->gss_names;
122 }
123
124 /* get the service name (i.e., gssname we see when we connect to this peer) */
125 TR_NAME *trp_peer_get_servicename(TRP_PEER *peer)
126 {
127   return peer->servicename;
128 }
129
130 /* get a copy of the servicename, caller must free via tr_free_name */
131 TR_NAME *trp_peer_dup_servicename(TRP_PEER *peer)
132 {
133   return tr_dup_name(peer->servicename);
134 }
135
136 unsigned int trp_peer_get_port(TRP_PEER *peer)
137 {
138   return peer->port;
139 }
140
141 void trp_peer_set_port(TRP_PEER *peer, unsigned int port)
142 {
143   peer->port=port;
144 }
145
146 unsigned int trp_peer_get_linkcost(TRP_PEER *peer)
147 {
148   if (peer!=NULL)
149     return peer->linkcost;
150   else
151     return 1;
152 }
153
154 void trp_peer_set_linkcost(TRP_PEER *peer, unsigned int linkcost)
155 {
156   if ((linkcost>TRP_METRIC_INFINITY) && (linkcost!=TRP_METRIC_INVALID)) {
157     /* This indicates a programming error, but probably means an already infinite metric
158      * was (incorrectly) incremented. Issue a warning and proceed with an infinite metric. */
159     tr_warning("trp_peer_set_linkcost: link cost > infinity encountered, setting to infinity");
160     linkcost=TRP_METRIC_INFINITY;
161   }
162   peer->linkcost=linkcost;
163 }
164
165 void trp_peer_set_conn_status_cb(TRP_PEER *peer, void (*cb)(TRP_PEER *, void *), void *cookie)
166 {
167   peer->conn_status_cb=cb;
168   peer->conn_status_cookie=cookie;
169 }
170
171 struct timespec *trp_peer_get_last_conn_attempt(TRP_PEER *peer)
172 {
173   return &(peer->last_conn_attempt);
174 }
175
176 void trp_peer_set_last_conn_attempt(TRP_PEER *peer, struct timespec *time)
177 {
178   peer->last_conn_attempt=*time;
179 }
180
181 TRP_PTABLE *trp_ptable_new(TALLOC_CTX *memctx)
182 {
183   TRP_PTABLE *ptbl=talloc(memctx, TRP_PTABLE);
184   if (ptbl!=NULL) {
185     ptbl->head=NULL;
186   }
187   return ptbl;
188 }
189
190 void trp_peer_set_outgoing_status(TRP_PEER *peer, TRP_PEER_CONN_STATUS status)
191 {
192   TR_NAME *peer_label=trp_peer_get_label(peer);
193   int was_connected=trp_peer_is_connected(peer);
194   peer->outgoing_status=status;
195   tr_debug("trp_peer_set_outgoing_status: %s: status=%d peer connected was %d now %d.",
196            peer_label->buf, status, was_connected, trp_peer_is_connected(peer));
197   if ((trp_peer_is_connected(peer) != was_connected) && (peer->conn_status_cb!=NULL))
198     peer->conn_status_cb(peer, peer->conn_status_cookie);
199 }
200
201 TRP_PEER_CONN_STATUS trp_peer_get_outgoing_status(TRP_PEER *peer)
202 {
203   return peer->outgoing_status;
204 }
205
206 void trp_peer_set_incoming_status(TRP_PEER *peer, TRP_PEER_CONN_STATUS status)
207 {
208   TR_NAME *peer_label=trp_peer_get_label(peer);
209   int was_connected=trp_peer_is_connected(peer);
210   peer->incoming_status=status;
211   tr_debug("trp_peer_set_incoming_status: %s: status=%d peer connected was %d now %d.",
212            peer_label->buf, status, was_connected, trp_peer_is_connected(peer));
213   if ((trp_peer_is_connected(peer) != was_connected) && (peer->conn_status_cb!=NULL))
214     peer->conn_status_cb(peer, peer->conn_status_cookie);
215 }
216
217 TRP_PEER_CONN_STATUS trp_peer_get_incoming_status(TRP_PEER *peer)
218 {
219   return peer->incoming_status;
220 }
221
222 int trp_peer_is_connected(TRP_PEER *peer)
223 {
224   return (peer->outgoing_status==PEER_CONNECTED) && (peer->incoming_status==PEER_CONNECTED);
225 }
226
227 void trp_ptable_free(TRP_PTABLE *ptbl)
228 {
229   talloc_free(ptbl);
230 }
231
232 TRP_RC trp_ptable_add(TRP_PTABLE *ptbl, TRP_PEER *newpeer)
233 {
234   if (ptbl->head==NULL)
235     ptbl->head=newpeer;
236   else
237     trp_peer_tail(ptbl->head)->next=newpeer;
238
239   talloc_steal(ptbl, newpeer);
240   return TRP_SUCCESS;
241 }
242
243 /* peer pointer is invalid after successful removal. Does nothing and returns
244  * TRP_ERROR if peer is not in the list. */
245 TRP_RC trp_ptable_remove(TRP_PTABLE *ptbl, TRP_PEER *peer)
246 {
247   TRP_PEER *cur=NULL;
248   TRP_PEER *last=NULL;
249   if (ptbl->head!=NULL) {
250     if (ptbl->head==peer) {
251       /* special case for removing head of list */
252       cur=ptbl->head;
253       ptbl->head=ptbl->head->next; /* advance the head */
254       trp_peer_free(cur);
255     }
256     for (cur=ptbl->head->next; cur!=NULL; last=cur,cur=cur->next) {
257       if (cur==peer) {
258         if (last!=NULL)
259           last->next=cur->next;
260         trp_peer_free(cur);
261         return TRP_SUCCESS;
262       }
263     }
264   }
265   return TRP_ERROR;
266 }
267
268 TRP_PEER *trp_ptable_find_gss_name(TRP_PTABLE *ptbl, TR_NAME *gssname)
269 {
270   TRP_PEER *cur=ptbl->head;
271   while ((cur!=NULL) && (!tr_gss_names_matches(trp_peer_get_gss_names(cur), gssname)))
272     cur=cur->next;
273   return cur;
274 }
275
276 TRP_PEER *trp_ptable_find_servicename(TRP_PTABLE *ptbl, TR_NAME *servicename)
277 {
278   TRP_PEER *cur=ptbl->head;
279   while ((cur!=NULL) && (0 != tr_name_cmp(trp_peer_get_servicename(cur), servicename)))
280     cur=cur->next;
281   return cur;
282 }
283
284 char *trp_peer_to_str(TALLOC_CTX *memctx, TRP_PEER *peer, const char *sep)
285 {
286   if (sep==NULL)
287     sep=", ";
288   return talloc_asprintf(memctx,
289                          "%s:%u%s0x%04X",
290                          peer->server, peer->port, sep,
291                          peer->linkcost);
292 }
293
294 /* this is horribly inefficient but should be ok for small peer tables */
295 char *trp_ptable_to_str(TALLOC_CTX *memctx, TRP_PTABLE *ptbl, const char *sep, const char *lineterm)
296 {
297   TALLOC_CTX *tmpctx=talloc_new(NULL);
298   TRP_PEER *peer=NULL;
299   char *result=talloc_strdup(tmpctx, "");
300
301   if (lineterm==NULL)
302     lineterm="\n";
303
304   /* this leaves intermediate result strings in the tmpctx context, we'll free these when
305    * we're done */
306   for (peer=ptbl->head; peer!=NULL; peer=peer->next)
307     result=talloc_asprintf(tmpctx, "%s%s%s", result, lineterm, trp_peer_to_str(tmpctx, peer, sep));
308
309   talloc_steal(memctx, result); /* hand result over to caller */
310   talloc_free(tmpctx); /* free detritus */
311   return result;
312 }
313
314 TRP_PTABLE_ITER *trp_ptable_iter_new(TALLOC_CTX *mem_ctx)
315 {
316   TRP_PTABLE_ITER *iter=talloc(mem_ctx, TRP_PTABLE_ITER);
317   *iter=NULL;
318   return iter;
319 }
320
321 TRP_PEER *trp_ptable_iter_first(TRP_PTABLE_ITER *iter, TRP_PTABLE *ptbl)
322 {
323   if (ptbl==NULL)
324     *iter=NULL;
325   else
326     *iter=ptbl->head;
327   return *iter;
328 }
329
330 TRP_PEER *trp_ptable_iter_next(TRP_PTABLE_ITER *iter)
331 {
332   if (*iter!=NULL)
333     *iter=(*iter)->next;
334   return *iter;
335 }
336
337 void trp_ptable_iter_free(TRP_PTABLE_ITER *iter)
338 {
339   talloc_free(iter);
340 }
341