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