Requests nearly work, but not quite.
[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 <trp_ptable.h>
7 #include <tr_debug.h>
8
9 static int trp_peer_destructor(void *object)
10 {
11   TRP_PEER *peer=talloc_get_type_abort(object, TRP_PEER);
12   if (peer->servicename!=NULL)
13     tr_free_name(peer->servicename);
14   if (peer->gssname!=NULL)
15     tr_free_name(peer->gssname);
16   return 0;
17 }
18 TRP_PEER *trp_peer_new(TALLOC_CTX *memctx)
19 {
20   TRP_PEER *peer=talloc(memctx, TRP_PEER);
21   if (peer!=NULL) {
22     peer->next=NULL;
23     peer->server=NULL;
24     peer->servicename=NULL;
25     peer->gssname=NULL;
26     peer->port=0;
27     peer->linkcost=TRP_LINKCOST_DEFAULT;
28     peer->last_conn_attempt=(struct timespec){0,0};
29     talloc_set_destructor((void *)peer, trp_peer_destructor);
30   }
31   return peer;
32 }
33
34 void trp_peer_free(TRP_PEER *peer)
35 {
36   talloc_free(peer);
37 }
38
39 static TRP_PEER *trp_peer_tail(TRP_PEER *peer)
40 {
41   while (peer->next!=NULL) {
42     peer=peer->next;
43   }
44   return peer;
45 }
46
47 char *trp_peer_get_server(TRP_PEER *peer)
48 {
49   return peer->server;
50 }
51
52 static void trp_peer_set_servicename(TRP_PEER *peer, const char *server)
53 {
54   char *name=NULL;
55   if (peer->servicename !=NULL)
56     tr_free_name(peer->servicename);
57
58   if (server!=NULL)
59     name=talloc_asprintf(NULL, "trustrouter/%s", server);
60
61   if (name!=NULL) {
62     peer->servicename=tr_new_name(name);
63     talloc_free(name);
64   } else {
65     peer->servicename=NULL;
66   }
67 }
68
69 /* copies input; on error, peer->gssname will be null */
70 void trp_peer_set_server(TRP_PEER *peer, char *server)
71 {
72   peer->server=talloc_strdup(peer, server); /* will be null on error */
73   trp_peer_set_servicename(peer, server);
74 }
75
76 void trp_peer_set_gssname(TRP_PEER *peer, TR_NAME *gssname)
77 {
78   peer->gssname=gssname;
79 }
80
81 /* get the peer gssname, caller must not free the result */
82 TR_NAME *trp_peer_get_gssname(TRP_PEER *peer)
83 {
84   return peer->gssname;
85 }
86
87 /* get a copy of the peer gssname, caller must free via tr_free_name() */
88 TR_NAME *trp_peer_dup_gssname(TRP_PEER *peer)
89 {
90   return tr_dup_name(peer->gssname);
91 }
92
93 /* get the service name (i.e., gssname we see when we connect to this peer) */
94 TR_NAME *trp_peer_get_servicename(TRP_PEER *peer)
95 {
96   return peer->servicename;
97 }
98
99 /* get a copy of the servicename, caller must free via tr_free_name */
100 TR_NAME *trp_peer_dup_servicename(TRP_PEER *peer)
101 {
102   return tr_dup_name(peer->servicename);
103 }
104
105 unsigned int trp_peer_get_port(TRP_PEER *peer)
106 {
107   return peer->port;
108 }
109
110 void trp_peer_set_port(TRP_PEER *peer, unsigned int port)
111 {
112   peer->port=port;
113 }
114
115 unsigned int trp_peer_get_linkcost(TRP_PEER *peer)
116 {
117   if (peer!=NULL)
118     return peer->linkcost;
119   else
120     return 1;
121 }
122
123 void trp_peer_set_linkcost(TRP_PEER *peer, unsigned int linkcost)
124 {
125   if ((linkcost>TRP_METRIC_INFINITY) && (linkcost!=TRP_METRIC_INVALID)) {
126     /* This indicates a programming error, but probably means an already infinite metric
127      * was (incorrectly) incremented. Issue a warning and proceed with an infinite metric. */
128     tr_warning("trp_peer_set_linkcost: link cost > infinity encountered, setting to infinity");
129     linkcost=TRP_METRIC_INFINITY;
130   }
131   peer->linkcost=linkcost;
132 }
133
134 struct timespec *trp_peer_get_last_conn_attempt(TRP_PEER *peer)
135 {
136   return &(peer->last_conn_attempt);
137 }
138
139 void trp_peer_set_last_conn_attempt(TRP_PEER *peer, struct timespec *time)
140 {
141   peer->last_conn_attempt=*time;
142 }
143
144 TRP_PTABLE *trp_ptable_new(TALLOC_CTX *memctx)
145 {
146   TRP_PTABLE *ptbl=talloc(memctx, TRP_PTABLE);
147   if (ptbl!=NULL) {
148     ptbl->head=NULL;
149   }
150   return ptbl;
151 }
152
153 void trp_ptable_free(TRP_PTABLE *ptbl)
154 {
155   talloc_free(ptbl);
156 }
157
158 TRP_RC trp_ptable_add(TRP_PTABLE *ptbl, TRP_PEER *newpeer)
159 {
160   if (ptbl->head==NULL) {
161     ptbl->head=newpeer;
162   } else {
163     trp_peer_tail(ptbl->head)->next=newpeer;
164     talloc_steal(ptbl, newpeer);
165   }
166   return TRP_SUCCESS;
167 }
168
169 /* peer pointer is invalid after successful removal. Does nothing and returns
170  * TRP_ERROR if peer is not in the list. */
171 TRP_RC trp_ptable_remove(TRP_PTABLE *ptbl, TRP_PEER *peer)
172 {
173   TRP_PEER *cur=NULL;
174   TRP_PEER *last=NULL;
175   if (ptbl->head!=NULL) {
176     if (ptbl->head==peer) {
177       /* special case for removing head of list */
178       cur=ptbl->head;
179       ptbl->head=ptbl->head->next; /* advance the head */
180       trp_peer_free(cur);
181     }
182     for (cur=ptbl->head->next; cur!=NULL; last=cur,cur=cur->next) {
183       if (cur==peer) {
184         if (last!=NULL)
185           last->next=cur->next;
186         trp_peer_free(cur);
187         return TRP_SUCCESS;
188       }
189     }
190   }
191   return TRP_ERROR;
192 }
193
194 TRP_PEER *trp_ptable_find_gssname(TRP_PTABLE *ptbl, TR_NAME *gssname)
195 {
196   TRP_PEER *cur=ptbl->head;
197   while ((cur!=NULL) && (0 != tr_name_cmp(trp_peer_get_gssname(cur), gssname)))
198     cur=cur->next;
199   return cur;
200 }
201
202 TRP_PEER *trp_ptable_find_servicename(TRP_PTABLE *ptbl, TR_NAME *servicename)
203 {
204   TRP_PEER *cur=ptbl->head;
205   while ((cur!=NULL) && (0 != tr_name_cmp(trp_peer_get_servicename(cur), servicename)))
206     cur=cur->next;
207   return cur;
208 }
209
210 char *trp_peer_to_str(TALLOC_CTX *memctx, TRP_PEER *peer, const char *sep)
211 {
212   if (sep==NULL)
213     sep=", ";
214   return talloc_asprintf(memctx,
215                          "%s:%u%s0x%04X",
216                          peer->server, peer->port, sep,
217                          peer->linkcost);
218 }
219
220 /* this is horribly inefficient but should be ok for small peer tables */
221 char *trp_ptable_to_str(TALLOC_CTX *memctx, TRP_PTABLE *ptbl, const char *sep, const char *lineterm)
222 {
223   TALLOC_CTX *tmpctx=talloc_new(NULL);
224   TRP_PEER *peer=NULL;
225   char *result=talloc_strdup(tmpctx, "");
226
227   if (lineterm==NULL)
228     lineterm="\n";
229
230   /* this leaves intermediate result strings in the tmpctx context, we'll free these when
231    * we're done */
232   for (peer=ptbl->head; peer!=NULL; peer=peer->next)
233     result=talloc_asprintf(tmpctx, "%s%s%s", result, lineterm, trp_peer_to_str(tmpctx, peer, sep));
234
235   talloc_steal(memctx, result); /* hand result over to caller */
236   talloc_free(tmpctx); /* free detritus */
237   return result;
238 }
239
240 TRP_PTABLE_ITER *trp_ptable_iter_new(TALLOC_CTX *mem_ctx)
241 {
242   TRP_PTABLE_ITER *iter=talloc(mem_ctx, TRP_PTABLE_ITER);
243   *iter=NULL;
244   return iter;
245 }
246
247 TRP_PEER *trp_ptable_iter_first(TRP_PTABLE_ITER *iter, TRP_PTABLE *ptbl)
248 {
249   *iter=ptbl->head;
250   return *iter;
251 }
252
253 TRP_PEER *trp_ptable_iter_next(TRP_PTABLE_ITER *iter)
254 {
255   *iter=(*iter)->next;
256   return *iter;
257 }
258
259 void trp_ptable_iter_free(TRP_PTABLE_ITER *iter)
260 {
261   talloc_free(iter);
262 }
263