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>
48 #include <log4cpp/Category.hh>
50 // Deal with inadequate Sun RPC libraries
52 #if !HAVE_DECL_SVCFD_CREATE
53 extern "C" SVCXPRT* svcfd_create(int, u_int, u_int);
56 #ifndef HAVE_WORKING_SVC_DESTROY
57 struct tcp_conn { /* kept in xprt->xp_p1 */
58 enum xprt_stat strm_stat;
61 char verf_body[MAX_AUTH_BYTES];
67 using namespace shibboleth;
68 using namespace shibtarget;
69 using namespace log4cpp;
72 map<IListener::ShibSocket,Thread*> children;
73 Mutex* child_lock = NULL;
74 CondWait* child_wait = NULL;
78 void* shar_client_thread (void* arg)
80 SharChild* child = (SharChild*)arg;
82 // First, let's block all signals
83 Thread::mask_all_signals();
85 ShibTargetConfig::getConfig().getINI()->getSessionCache()->thread_init();
86 ShibTargetConfig::getConfig().getINI()->getReplayCache()->thread_init();
88 // the run the child until they exit.
91 ShibTargetConfig::getConfig().getINI()->getSessionCache()->thread_end();
92 ShibTargetConfig::getConfig().getINI()->getReplayCache()->thread_end();
94 // now we can clean up and exit the thread.
99 SharChild::SharChild(IListener::ShibSocket& s, const Iterator<ShibRPCProtocols>& protos) : sock(s), child(NULL)
102 while (protos.hasNext())
103 v_protos.push_back(protos.next());
105 // Create the child thread
106 child = Thread::create(shar_client_thread, (void*)this);
110 SharChild::~SharChild()
112 // Then lock the children map, remove this socket/thread, signal waiters, and return
114 children.erase(sock);
115 child_lock->unlock();
116 child_wait->signal();
121 void SharChild::run()
123 // Before starting up, make sure we fully "own" this socket.
125 while (children.find(sock)!=children.end())
126 child_wait->wait(child_lock);
127 children[sock] = child;
128 child_lock->unlock();
134 struct timeval tv = { 0, 0 };
136 while(running && FD_ISSET(sock, &svc_fdset)) {
138 FD_SET(sock, &readfds);
141 switch (select(sock+1, &readfds, 0, 0, &tv)) {
147 if (errno == EINTR) continue;
148 SHARUtils::log_error();
149 Category::getInstance("SHAR.SharChild").error("select() on incoming request socket (%u) returned error",sock);
156 svc_getreqset(&readfds);
161 bool SharChild::svc_create()
163 /* Wrap an RPC Service around the new connection socket. */
164 SVCXPRT* transp = svcfd_create(sock, 0, 0);
166 NDC ndc("svc_create");
167 Category::getInstance("SHAR.SharChild").error("cannot create RPC listener");
171 /* Register the SHIBRPC RPC Program */
172 Iterator<ShibRPCProtocols> i(v_protos);
173 while (i.hasNext()) {
174 const ShibRPCProtocols& p=i.next();
175 if (!svc_register (transp, p.prog, p.vers, p.dispatch, 0)) {
176 #ifdef HAVE_WORKING_SVC_DESTROY
179 /* we have to inline svc_destroy because we can't pass in the xprt variable */
180 struct tcp_conn *cd = (struct tcp_conn *)transp->xp_p1;
181 xprt_unregister(transp);
182 close(transp->xp_sock);
183 if (transp->xp_port != 0) {
184 /* a rendezvouser socket */
187 /* an actual connection socket */
188 XDR_DESTROY(&(cd->xdrs));
190 mem_free((caddr_t)cd, sizeof(struct tcp_conn));
191 mem_free((caddr_t)transp, sizeof(SVCXPRT));
193 NDC ndc("svc_create");
194 Category::getInstance("SHAR.SharChild").error("cannot register RPC program");
201 void SHARUtils::log_error()
204 int rc=WSAGetLastError();
208 #ifdef HAVE_STRERROR_R
210 strerror_r(rc,buf,sizeof(buf));
212 Category::getInstance("SHAR.SHARUtils").error("system call resulted in error (%d): %s",rc,buf);
214 Category::getInstance("SHAR.SHARUtils").error("system call resulted in error (%d): %s",rc,strerror(rc));
218 void SHARUtils::init()
220 child_lock = Mutex::create();
221 child_wait = CondWait::create();
225 void SHARUtils::fini()
229 // wait for all children to exit.
231 while (children.size())
232 child_wait->wait(child_lock);
233 child_lock->unlock();