Annotate exceptions with issuer in place of parameter.
[shibboleth/sp.git] / shib-target / shib-rpchandle.cpp
1 /*
2  * The Shibboleth License, Version 1.
3  * Copyright (c) 2002
4  * University Corporation for Advanced Internet Development, Inc.
5  * All rights reserved
6  *
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions are met:
10  *
11  * Redistributions of source code must retain the above copyright notice, this
12  * list of conditions and the following disclaimer.
13  *
14  * Redistributions in binary form must reproduce the above copyright notice,
15  * this list of conditions and the following disclaimer in the documentation
16  * and/or other materials provided with the distribution, if any, must include
17  * the following acknowledgment: "This product includes software developed by
18  * the University Corporation for Advanced Internet Development
19  * <http://www.ucaid.edu>Internet2 Project. Alternately, this acknowledegement
20  * may appear in the software itself, if and wherever such third-party
21  * acknowledgments normally appear.
22  *
23  * Neither the name of Shibboleth nor the names of its contributors, nor
24  * Internet2, nor the University Corporation for Advanced Internet Development,
25  * Inc., nor UCAID may be used to endorse or promote products derived from this
26  * software without specific prior written permission. For written permission,
27  * please contact shibboleth@shibboleth.org
28  *
29  * Products derived from this software may not be called Shibboleth, Internet2,
30  * UCAID, or the University Corporation for Advanced Internet Development, nor
31  * may Shibboleth appear in their name, without prior written permission of the
32  * University Corporation for Advanced Internet Development.
33  *
34  *
35  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
36  * AND WITH ALL FAULTS. ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
37  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
38  * PARTICULAR PURPOSE, AND NON-INFRINGEMENT ARE DISCLAIMED AND THE ENTIRE RISK
39  * OF SATISFACTORY QUALITY, PERFORMANCE, ACCURACY, AND EFFORT IS WITH LICENSEE.
40  * IN NO EVENT SHALL THE COPYRIGHT OWNER, CONTRIBUTORS OR THE UNIVERSITY
41  * CORPORATION FOR ADVANCED INTERNET DEVELOPMENT, INC. BE LIABLE FOR ANY DIRECT,
42  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
43  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
44  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
45  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
46  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
47  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
48  */
49
50 /*
51  * shib-rpchandle.cpp -- the RPC Handle abstraction
52  *
53  * Created by:  Derek Atkins <derek@ihtfp.com>
54  *
55  * $Id$
56  */
57
58 #include "internal.h"
59
60 #ifdef HAVE_UNISTD_H
61 # include <unistd.h>
62 #endif
63 #include <shib/shib-threads.h>
64
65 #include <stdexcept>
66 #include <log4cpp/Category.hh>
67
68 using namespace std;
69 using namespace log4cpp;
70 using namespace saml;
71 using namespace shibboleth;
72 using namespace shibtarget;
73
74 RPCHandle::RPCHandle() : m_clnt(NULL), m_sock((IListener::ShibSocket)0), log(&(log4cpp::Category::getInstance("shibtarget.RPCHandle")))
75 {
76     log->debug("New RPCHandle created: %p", this);
77 }
78
79 RPCHandle::~RPCHandle()
80 {
81     log->debug("Destroying RPC Handle: %p", this);
82     disconnect();
83 }
84
85 void RPCHandle::disconnect()
86 {
87     if (m_clnt) {
88         clnt_destroy(m_clnt);
89         m_clnt=NULL;
90         IConfig* conf=ShibTargetConfig::getConfig().getINI();
91         if (conf) {
92             Locker locker(conf);
93             conf->getListener()->close(m_sock);
94             m_sock=(IListener::ShibSocket)0;
95         }
96         else
97             m_sock=(IListener::ShibSocket)0;
98     }
99 }
100
101 CLIENT* RPCHandle::connect()
102 {
103     saml::NDC ndc("connect");
104
105     if (m_clnt) {
106         log->debug ("returning existing connection: %p -> %p", this, m_clnt);
107         return m_clnt;
108     }
109
110     log->debug("trying to connect to SHAR");
111
112     IListener::ShibSocket sock;
113     IConfig* conf=ShibTargetConfig::getConfig().getINI();
114     Locker locker(conf);
115     const IListener* listener=conf->getListener();
116     if (!listener->create(sock)) {
117         log->error("cannot create socket");
118         throw ShibTargetException(SHIBRPC_UNKNOWN_ERROR, "Cannot create socket");
119     }
120
121     bool connected = false;
122     int num_tries = 3;
123
124     for (int i = num_tries-1; i >= 0; i--) {
125         if (listener->connect(sock)) {
126             connected = true;
127             break;
128         }
129     
130         log->warn ("cannot connect %p to SHAR... %s", this, (i > 0 ? "retrying" : ""));
131
132         if (i)
133 #ifdef WIN32
134             Sleep(2000*(num_tries-i));
135 #else
136             sleep(2*(num_tries-i));
137 #endif
138     }
139
140     if (!connected) {
141         log->crit("SHAR Unavailable..  Failing.");
142         listener->close(sock);
143         throw ShibTargetException(SHIBRPC_UNKNOWN_ERROR, "Cannot connect to SHAR process, target site adminstrator should be notified");
144     }
145
146     CLIENT *clnt = listener->getClientHandle(sock, SHIBRPC_PROG, SHIBRPC_VERS_2);
147     if (!clnt) {
148         const char* rpcerror = clnt_spcreateerror("RPCHandle::connect");
149         log->crit("RPC failed for %p: %s", this, rpcerror);
150         listener->close(sock);
151         throw ShibTargetException(SHIBRPC_UNKNOWN_ERROR, rpcerror);
152     }
153
154     // Set the RPC timeout to a fairly high value...
155     struct timeval tv;
156     tv.tv_sec = 300;    /* change timeout to 5 minutes */
157     tv.tv_usec = 0;     /* this should always be set  */
158     clnt_control(clnt, CLSET_TIMEOUT, (char*)&tv);
159
160     m_clnt = clnt;
161     m_sock = sock;
162
163     log->debug("success: %p -> %p", this, m_clnt);
164     return m_clnt;
165 }
166
167 RPCHandlePool::~RPCHandlePool()
168 {
169     while (!m_pool.empty()) {
170         delete m_pool.top();
171         m_pool.pop();
172     }
173 }
174
175 RPCHandle* RPCHandlePool::get()
176 {
177     m_lock->lock();
178     if (m_pool.empty()) {
179         m_lock->unlock();
180         return new RPCHandle();
181     }
182     RPCHandle* ret=m_pool.top();
183     m_pool.pop();
184     m_lock->unlock();
185     return ret;
186 }
187
188 void RPCHandlePool::put(RPCHandle* handle)
189 {
190     m_lock->lock();
191     m_pool.push(handle);
192     m_lock->unlock();
193 }
194
195 RPC::RPC() : m_pool(dynamic_cast<STConfig&>(ShibTargetConfig::getConfig()).getRPCHandlePool())
196 {
197     m_handle=m_pool.get();
198 }