2 * Copyright 2001-2005 Internet2
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
18 * shar-utils.cpp -- utility functions for the SHAR
20 * Created By: Derek Atkins <derek@ihtfp.com>
25 // eventually we might be able to support autoconf via cygwin...
26 #if defined (_MSC_VER) || defined(__BORLANDC__)
27 # include "config_win32.h"
33 # define FD_SETSIZE 1024
38 # include <sys/select.h>
45 #include "shar-utils.h"
47 #include <shib/shib-threads.h>
49 // Deal with inadequate Sun RPC libraries
51 #if !HAVE_DECL_SVCFD_CREATE
52 extern "C" SVCXPRT* svcfd_create(int, u_int, u_int);
55 #ifndef HAVE_WORKING_SVC_DESTROY
56 struct tcp_conn { /* kept in xprt->xp_p1 */
57 enum xprt_stat strm_stat;
60 char verf_body[MAX_AUTH_BYTES];
66 using namespace shibboleth;
67 using namespace shibtarget;
68 using namespace shibd::logging;
71 map<IListener::ShibSocket,Thread*> children;
72 Mutex* child_lock = NULL;
73 CondWait* child_wait = NULL;
77 void* shar_client_thread (void* arg)
79 SharChild* child = (SharChild*)arg;
81 // First, let's block all signals
82 Thread::mask_all_signals();
84 ShibTargetConfig::getConfig().getINI()->getSessionCache()->thread_init();
85 ShibTargetConfig::getConfig().getINI()->getReplayCache()->thread_init();
87 // the run the child until they exit.
90 ShibTargetConfig::getConfig().getINI()->getSessionCache()->thread_end();
91 ShibTargetConfig::getConfig().getINI()->getReplayCache()->thread_end();
93 // now we can clean up and exit the thread.
98 SharChild::SharChild(IListener::ShibSocket& s, const Iterator<ShibRPCProtocols>& protos) : sock(s), child(NULL)
101 while (protos.hasNext())
102 v_protos.push_back(protos.next());
104 // Create the child thread
105 child = Thread::create(shar_client_thread, (void*)this);
109 SharChild::~SharChild()
111 // Then lock the children map, remove this socket/thread, signal waiters, and return
113 children.erase(sock);
114 child_lock->unlock();
115 child_wait->signal();
120 void SharChild::run()
122 // Before starting up, make sure we fully "own" this socket.
124 while (children.find(sock)!=children.end())
125 child_wait->wait(child_lock);
126 children[sock] = child;
127 child_lock->unlock();
133 struct timeval tv = { 0, 0 };
135 while(running && FD_ISSET(sock, &svc_fdset)) {
137 FD_SET(sock, &readfds);
140 switch (select(sock+1, &readfds, 0, 0, &tv)) {
146 if (errno == EINTR) continue;
147 SHARUtils::log_error();
148 Category::getInstance("SHAR.SharChild").error("select() on incoming request socket (%u) returned error",sock);
155 svc_getreqset(&readfds);
160 bool SharChild::svc_create()
162 /* Wrap an RPC Service around the new connection socket. */
163 SVCXPRT* transp = svcfd_create(sock, 0, 0);
165 NDC ndc("svc_create");
166 Category::getInstance("SHAR.SharChild").error("cannot create RPC listener");
170 /* Register the SHIBRPC RPC Program */
171 Iterator<ShibRPCProtocols> i(v_protos);
172 while (i.hasNext()) {
173 const ShibRPCProtocols& p=i.next();
174 if (!svc_register (transp, p.prog, p.vers, p.dispatch, 0)) {
175 #ifdef HAVE_WORKING_SVC_DESTROY
178 /* we have to inline svc_destroy because we can't pass in the xprt variable */
179 struct tcp_conn *cd = (struct tcp_conn *)transp->xp_p1;
180 xprt_unregister(transp);
181 close(transp->xp_sock);
182 if (transp->xp_port != 0) {
183 /* a rendezvouser socket */
186 /* an actual connection socket */
187 XDR_DESTROY(&(cd->xdrs));
189 mem_free((caddr_t)cd, sizeof(struct tcp_conn));
190 mem_free((caddr_t)transp, sizeof(SVCXPRT));
192 NDC ndc("svc_create");
193 Category::getInstance("SHAR.SharChild").error("cannot register RPC program");
200 void SHARUtils::log_error()
203 int rc=WSAGetLastError();
207 #ifdef HAVE_STRERROR_R
209 strerror_r(rc,buf,sizeof(buf));
211 Category::getInstance("SHAR.SHARUtils").error("system call resulted in error (%d): %s",rc,buf);
213 Category::getInstance("SHAR.SHARUtils").error("system call resulted in error (%d): %s",rc,strerror(rc));
217 void SHARUtils::init()
219 child_lock = Mutex::create();
220 child_wait = CondWait::create();
224 void SHARUtils::fini()
228 // wait for all children to exit.
230 while (children.size())
231 child_wait->wait(child_lock);
232 child_lock->unlock();