34d4296caef7543aa68f62129af008bc4c3be96c
[trust_router.git] / trp / trp_peer.c
1 /*
2  * Copyright (c) 2016-2018, JANET(UK)
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  *
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  *
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  *
16  * 3. Neither the name of JANET(UK) nor the names of its contributors
17  *    may be used to endorse or promote products derived from this software
18  *    without specific prior written permission.
19  *
20  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
23  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
24  * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
25  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
26  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
27  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
29  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
30  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
31  * OF THE POSSIBILITY OF SUCH DAMAGE.
32  *
33  */
34
35 #include <time.h>
36 #include <talloc.h>
37
38 #include <tr_name_internal.h>
39 #include <trp_internal.h>
40 #include <tr_gss_names.h>
41 #include <trp_ptable.h>
42 #include <tr_debug.h>
43 #include <trp_peer.h>
44
45 static int trp_peer_destructor(void *object)
46 {
47   TRP_PEER *peer=talloc_get_type_abort(object, TRP_PEER);
48   if (peer->label!=NULL)
49     tr_free_name(peer->label);
50   if (peer->servicename!=NULL)
51     tr_free_name(peer->servicename);
52   return 0;
53 }
54 TRP_PEER *trp_peer_new(TALLOC_CTX *memctx)
55 {
56   TRP_PEER *peer=talloc(memctx, TRP_PEER);
57   if (peer!=NULL) {
58     peer->next=NULL;
59     peer->label=NULL;
60     peer->server=NULL;
61     peer->servicename=NULL;
62     peer->gss_names=NULL;
63     peer->port=0;
64     peer->linkcost=TRP_LINKCOST_DEFAULT;
65     peer->last_conn_attempt=(struct timespec){0,0};
66     peer->outgoing_status=PEER_DISCONNECTED;
67     peer->incoming_status=PEER_DISCONNECTED;
68     peer->conn_status_cb=NULL;
69     peer->conn_status_cookie=NULL;
70     peer->filters=NULL;
71     talloc_set_destructor((void *)peer, trp_peer_destructor);
72   }
73   return peer;
74 }
75
76 void trp_peer_free(TRP_PEER *peer)
77 {
78   talloc_free(peer);
79 }
80
81 TRP_PEER *trp_peer_tail(TRP_PEER *peer)
82 {
83   while (peer->next!=NULL) {
84     peer=peer->next;
85   }
86   return peer;
87 }
88
89
90 /* Get a name that identifies this peer for display to the user, etc.
91  * Do not modify or free the label. */
92 TR_NAME *trp_peer_get_label(TRP_PEER *peer)
93 {
94   char *s=NULL;
95
96   if (peer->label==NULL) {
97     s=talloc_asprintf(NULL, "%s:%u", peer->server, peer->port);
98     if (s!=NULL) {
99       peer->label=tr_new_name(s);
100       talloc_free(s);
101     }
102   }
103   return peer->label;
104 }
105
106 /* Get a name that identifies this peer for display to the user, etc.
107  * Makes a copy, caller is responsible for freeing.  */
108 TR_NAME *trp_peer_dup_label(TRP_PEER *peer)
109 {
110   return tr_dup_name(trp_peer_get_label(peer));;
111 }
112
113 char *trp_peer_get_server(TRP_PEER *peer)
114 {
115   return peer->server;
116 }
117
118 static void trp_peer_set_servicename(TRP_PEER *peer, const char *server)
119 {
120   char *name=NULL;
121   if (peer->servicename !=NULL)
122     tr_free_name(peer->servicename);
123
124   if (server!=NULL)
125     name=talloc_asprintf(NULL, "trustrouter/%s", server);
126
127   if (name!=NULL) {
128     peer->servicename=tr_new_name(name);
129     talloc_free(name);
130   } else {
131     peer->servicename=NULL;
132   }
133 }
134
135 /* copies input; on error, peer->servicename will be null */
136 void trp_peer_set_server(TRP_PEER *peer, const char *server)
137 {
138   peer->server=talloc_strdup(peer, server); /* will be null on error */
139   trp_peer_set_servicename(peer, server);
140 }
141
142 void trp_peer_add_gss_name(TRP_PEER *peer, TR_NAME *gss_name)
143 {
144   if (peer->gss_names==NULL)
145     trp_peer_set_gss_names(peer, tr_gss_names_new(peer));
146   tr_gss_names_add(peer->gss_names, gss_name);
147 }
148
149 void trp_peer_set_gss_names(TRP_PEER *peer, TR_GSS_NAMES *gss_names)
150 {
151   if (peer->gss_names!=NULL)
152     tr_gss_names_free(peer->gss_names);
153
154   peer->gss_names=gss_names;
155   talloc_steal(peer, gss_names);
156 }
157
158 /* get the peer gss_names, caller must not free the result */
159 TR_GSS_NAMES *trp_peer_get_gss_names(TRP_PEER *peer)
160 {
161   return peer->gss_names;
162 }
163
164 /* get the service name (i.e., gssname we see when we connect to this peer) */
165 TR_NAME *trp_peer_get_servicename(TRP_PEER *peer)
166 {
167   return peer->servicename;
168 }
169
170 /* get a copy of the servicename, caller must free via tr_free_name */
171 TR_NAME *trp_peer_dup_servicename(TRP_PEER *peer)
172 {
173   return tr_dup_name(peer->servicename);
174 }
175
176 int trp_peer_get_port(TRP_PEER *peer)
177 {
178   return peer->port;
179 }
180
181 void trp_peer_set_port(TRP_PEER *peer, int port)
182 {
183   peer->port=port;
184 }
185
186 unsigned int trp_peer_get_linkcost(TRP_PEER *peer)
187 {
188   if (peer!=NULL)
189     return peer->linkcost;
190   else
191     return 1;
192 }
193
194 void trp_peer_set_linkcost(TRP_PEER *peer, unsigned int linkcost)
195 {
196   if ((linkcost>TRP_METRIC_INFINITY) && (linkcost!=TRP_METRIC_INVALID)) {
197     /* This indicates a programming error, but probably means an already infinite metric
198      * was (incorrectly) incremented. Issue a warning and proceed with an infinite metric. */
199     tr_warning("trp_peer_set_linkcost: link cost > infinity encountered, setting to infinity");
200     linkcost=TRP_METRIC_INFINITY;
201   }
202   peer->linkcost=linkcost;
203 }
204
205 void trp_peer_set_conn_status_cb(TRP_PEER *peer, void (*cb)(TRP_PEER *, void *), void *cookie)
206 {
207   peer->conn_status_cb=cb;
208   peer->conn_status_cookie=cookie;
209 }
210
211 /**
212  * Set the filter associated with this peer. Any existing filter will be freed. Takes responsibility for
213  * freeing the new filter.
214  *
215  * @param peer Peer to modify
216  * @param filts New filter to attach to the peer
217  */
218 void trp_peer_set_filters(TRP_PEER *peer, TR_FILTER_SET *filts)
219 {
220   if (peer->filters!=NULL)
221     tr_filter_set_free(peer->filters);
222
223   peer->filters=filts;
224   talloc_steal(peer, filts);
225 }
226
227 TR_FILTER *trp_peer_get_filter(TRP_PEER *peer, TR_FILTER_TYPE ftype)
228 {
229   return tr_filter_set_get(peer->filters, ftype);
230 }
231
232 struct timespec *trp_peer_get_last_conn_attempt(TRP_PEER *peer)
233 {
234   return &(peer->last_conn_attempt);
235 }
236
237 void trp_peer_set_last_conn_attempt(TRP_PEER *peer, struct timespec *time)
238 {
239   peer->last_conn_attempt=*time;
240 }
241
242 void trp_peer_set_outgoing_status(TRP_PEER *peer, TRP_PEER_CONN_STATUS status)
243 {
244   TR_NAME *peer_label=trp_peer_get_label(peer);
245   int was_connected=trp_peer_is_connected(peer);
246   peer->outgoing_status=status;
247   tr_debug("trp_peer_set_outgoing_status: %s: status=%d peer connected was %d now %d.",
248            peer_label->buf, status, was_connected, trp_peer_is_connected(peer));
249   if ((trp_peer_is_connected(peer) != was_connected) && (peer->conn_status_cb!=NULL))
250     peer->conn_status_cb(peer, peer->conn_status_cookie);
251 }
252
253 TRP_PEER_CONN_STATUS trp_peer_get_outgoing_status(TRP_PEER *peer)
254 {
255   return peer->outgoing_status;
256 }
257
258 void trp_peer_set_incoming_status(TRP_PEER *peer, TRP_PEER_CONN_STATUS status)
259 {
260   TR_NAME *peer_label=trp_peer_get_label(peer);
261   int was_connected=trp_peer_is_connected(peer);
262   peer->incoming_status=status;
263   tr_debug("trp_peer_set_incoming_status: %s: status=%d peer connected was %d now %d.",
264            peer_label->buf, status, was_connected, trp_peer_is_connected(peer));
265   if ((trp_peer_is_connected(peer) != was_connected) && (peer->conn_status_cb!=NULL))
266     peer->conn_status_cb(peer, peer->conn_status_cookie);
267 }
268
269 TRP_PEER_CONN_STATUS trp_peer_get_incoming_status(TRP_PEER *peer)
270 {
271   return peer->incoming_status;
272 }
273
274 int trp_peer_is_connected(TRP_PEER *peer)
275 {
276   return (peer->outgoing_status==PEER_CONNECTED) && (peer->incoming_status==PEER_CONNECTED);
277 }