Merge pull request #76 from painless-security/jennifer/trpc_deadlock
[trust_router.git] / trp / trpc.c
1 /*
2  * Copyright (c) 2016, 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 <fcntl.h>
36 #include <talloc.h>
37 #include <errno.h>
38 #include <unistd.h>
39
40 #include <gsscon.h>
41 #include <tr_rp.h>
42 #include <tr_debug.h>
43 #include <trp_internal.h>
44
45 static int trpc_destructor(void *object)
46 {
47   TRPC_INSTANCE *trpc=talloc_get_type_abort(object, TRPC_INSTANCE);
48   if (trpc->gssname!=NULL)
49     tr_free_name(trpc->gssname);
50   return 0;
51 }
52
53 /* also allocates the incoming mq */
54 TRPC_INSTANCE *trpc_new (TALLOC_CTX *mem_ctx)
55 {
56   TRPC_INSTANCE *trpc=talloc(mem_ctx, TRPC_INSTANCE);
57   if (trpc!=NULL) {
58     trpc->next=NULL;
59     trpc->server=NULL;
60     trpc->port=0;
61     trpc->conn=NULL;
62     trpc->mq=tr_mq_new(trpc);
63     if (trpc->mq==NULL) {
64       talloc_free(trpc);
65       trpc=NULL;
66     } else
67       talloc_set_destructor((void *)trpc, trpc_destructor);
68     
69   }
70   return trpc;
71 }
72
73 void trpc_free (TRPC_INSTANCE *trpc)
74 {
75   if (trpc)
76     talloc_free(trpc);
77 }
78
79 TRPC_INSTANCE *trpc_get_next(TRPC_INSTANCE *trpc)
80 {
81   return trpc->next;
82 }
83
84 void trpc_set_next(TRPC_INSTANCE *trpc, TRPC_INSTANCE *next)
85 {
86   trpc->next=next;
87 }
88
89 /* Ok to call more than once; guarantees trpc no longer in the list. Does not free removed element.
90  * Returns handle to new list, you must replace your old handle on the list with this.  */
91 TRPC_INSTANCE *trpc_remove(TRPC_INSTANCE *trpc, TRPC_INSTANCE *remove)
92 {
93   TRPC_INSTANCE *cur=trpc;
94   TRPC_INSTANCE *last=NULL;
95
96   if (cur==NULL)
97     return NULL;
98
99   /* first element is a special case */
100   if (cur==remove) {
101     trpc=trpc_get_next(cur); /* advance list head */
102   } else {
103     /* it was not the first element */
104     last=cur;
105     cur=trpc_get_next(cur);
106     while (cur!=NULL) {
107       if (cur==remove) {
108         trpc_set_next(last, trpc_get_next(cur));
109         break;
110       }
111       last=cur;
112       cur=trpc_get_next(cur);
113     }
114   }
115   return trpc;
116 }
117
118 static TRPC_INSTANCE *trpc_get_tail(TRPC_INSTANCE *trpc)
119 {
120   while((trpc!=NULL)&&(trpc_get_next(trpc)!=NULL))
121     trpc=trpc_get_next(trpc);
122   return trpc;
123 }
124
125 void trpc_append(TRPC_INSTANCE *trpc, TRPC_INSTANCE *new)
126 {
127   trpc_set_next(trpc_get_tail(trpc), new);
128 }
129
130 char *trpc_get_server(TRPC_INSTANCE *trpc)
131 {
132   return trpc->server;
133 }
134
135 void trpc_set_server(TRPC_INSTANCE *trpc, char *server)
136 {
137   trpc->server=server;
138 }
139
140 TR_NAME *trpc_get_gssname(TRPC_INSTANCE *trpc)
141 {
142   return trpc->gssname;
143 }
144
145 /* takes responsibility for freeing gssname */
146 void trpc_set_gssname(TRPC_INSTANCE *trpc, TR_NAME *gssname)
147 {
148   trpc->gssname=gssname;
149 }
150
151 unsigned int trpc_get_port(TRPC_INSTANCE *trpc)
152 {
153   return trpc->port;
154 }
155
156 void trpc_set_port(TRPC_INSTANCE *trpc, unsigned int port)
157 {
158   trpc->port=port;
159 }
160
161 TRP_CONNECTION *trpc_get_conn(TRPC_INSTANCE *trpc)
162 {
163   return trpc->conn;
164 }
165
166 void trpc_set_conn(TRPC_INSTANCE *trpc, TRP_CONNECTION *conn)
167 {
168   trpc->conn=conn;
169 }
170
171 TRP_CONNECTION_STATUS trpc_get_status(TRPC_INSTANCE *trpc)
172 {
173   return trp_connection_get_status(trpc_get_conn(trpc));
174 }
175
176 TR_MQ *trpc_get_mq(TRPC_INSTANCE *trpc)
177 {
178   return trpc->mq;
179 }
180
181 void trpc_set_mq(TRPC_INSTANCE *trpc, TR_MQ *mq)
182 {
183   trpc->mq=mq;
184 }
185
186 /* submit msg to trpc for transmission */
187 void trpc_mq_add(TRPC_INSTANCE *trpc, TR_MQ_MSG *msg)
188 {
189   tr_mq_add(trpc->mq, msg);
190 }
191
192 TR_MQ_MSG *trpc_mq_pop(TRPC_INSTANCE *trpc, struct timespec *ts_abort)
193 {
194   return tr_mq_pop(trpc->mq, ts_abort);
195 }
196
197 void trpc_mq_clear(TRPC_INSTANCE *trpc)
198 {
199   tr_mq_clear(trpc->mq);
200 }
201
202 TRP_RC trpc_connect(TRPC_INSTANCE *trpc)
203 {
204   return trp_connection_initiate(trpc_get_conn(trpc), trpc_get_server(trpc), trpc_get_port(trpc));
205 }
206
207 /* simple function, based on tidc_send_req */
208 TRP_RC trpc_send_msg (TRPC_INSTANCE *trpc, 
209                       const char *msg_content)
210 {
211   int err=0;
212   TRP_RC rc=TRP_SUCCESS;
213
214   /* Send the request over the connection */
215   if (err = gsscon_write_encrypted_token(trp_connection_get_fd(trpc_get_conn(trpc)),
216                                          *trp_connection_get_gssctx(trpc_get_conn(trpc)),
217                                          msg_content, 
218                                          strlen(msg_content))) {
219     tr_err( "trpc_send_msg: Error sending message over connection.");
220     rc=TRP_ERROR;
221   }
222   return rc;
223 }