2 * Copyright 2001-2010 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.
20 * TCP-based SocketListener implementation.
24 #include "remoting/impl/SocketListener.h"
26 #include <xercesc/util/XMLUniDefs.hpp>
27 #include <xmltooling/unicode.h>
28 #include <xmltooling/util/XMLHelper.h>
31 # include <sys/socket.h>
34 # include <arpa/inet.h>
35 # include <netinet/in.h>
38 #include <sys/types.h>
39 #include <sys/stat.h> /* for chmod() */
44 using namespace shibsp;
45 using namespace xmltooling;
46 using namespace xercesc;
50 class TCPListener : virtual public SocketListener
53 TCPListener(const DOMElement* e);
56 bool create(ShibSocket& s) const;
57 bool bind(ShibSocket& s, bool force=false) const;
58 bool connect(ShibSocket& s) const;
59 bool close(ShibSocket& s) const;
60 bool accept(ShibSocket& listener, ShibSocket& s) const;
62 int send(ShibSocket& s, const char* buf, int len) const {
63 return ::send(s, buf, len, 0);
66 int recv(ShibSocket& s, char* buf, int buflen) const {
67 return ::recv(s, buf, buflen, 0);
71 void setup_tcp_sockaddr(struct sockaddr_in* addr) const;
74 unsigned short m_port;
78 ListenerService* SHIBSP_DLLLOCAL TCPListenerServiceFactory(const DOMElement* const & e)
80 return new TCPListener(e);
83 static const XMLCh address[] = UNICODE_LITERAL_7(a,d,d,r,e,s,s);
84 static const XMLCh port[] = UNICODE_LITERAL_4(p,o,r,t);
85 static const XMLCh acl[] = UNICODE_LITERAL_3(a,c,l);
88 TCPListener::TCPListener(const DOMElement* e)
90 m_address(XMLHelper::getAttrString(e, getenv("SHIBSP_LISTENER_ADDRESS"), address)),
91 m_port(XMLHelper::getAttrInt(e, 0, port))
93 if (m_address.empty())
94 m_address = "127.0.0.1";
97 const char* p = getenv("SHIBSP_LISTENER_PORT");
105 string sockacl = XMLHelper::getAttrString(e, "127.0.0.1", acl);
106 for (unsigned int i = 0; i < sockacl.length(); i++) {
107 if (sockacl.at(i) == ' ') {
108 m_acl.insert(sockacl.substr(j, i-j));
112 m_acl.insert(sockacl.substr(j, sockacl.length()-j));
115 void TCPListener::setup_tcp_sockaddr(struct sockaddr_in* addr) const
117 // Split on host:port boundary. Default to port only.
118 memset(addr,0,sizeof(struct sockaddr_in));
119 addr->sin_family=AF_INET;
120 addr->sin_port=htons(m_port);
121 addr->sin_addr.s_addr=inet_addr(m_address.c_str());
124 bool TCPListener::create(ShibSocket& s) const
126 s=socket(AF_INET,SOCK_STREAM,0);
128 if(s==INVALID_SOCKET)
136 bool TCPListener::bind(ShibSocket& s, bool force) const
138 struct sockaddr_in addr;
139 setup_tcp_sockaddr(&addr);
141 // XXX: Do we care about the return value from setsockopt?
143 ::setsockopt(s, SOL_SOCKET, SO_REUSEADDR, (const char*)&opt, sizeof(opt));
146 if (SOCKET_ERROR==::bind(s,(struct sockaddr *)&addr,sizeof(addr)) || SOCKET_ERROR==::listen(s,3)) {
152 if (::bind(s, (struct sockaddr *)&addr, sizeof (addr)) < 0) {
162 bool TCPListener::connect(ShibSocket& s) const
164 struct sockaddr_in addr;
165 setup_tcp_sockaddr(&addr);
167 if(SOCKET_ERROR==::connect(s,(struct sockaddr *)&addr,sizeof(addr)))
170 if (::connect(s, (struct sockaddr*)&addr, sizeof (addr)) < 0)
176 bool TCPListener::close(ShibSocket& s) const
186 bool TCPListener::accept(ShibSocket& listener, ShibSocket& s) const
188 struct sockaddr_in addr;
191 int size=sizeof(addr);
192 s=::accept(listener,(struct sockaddr*)&addr,&size);
193 if(s==INVALID_SOCKET)
195 socklen_t size=sizeof(addr);
196 s=::accept(listener,(struct sockaddr*)&addr,&size);
200 char* client=inet_ntoa(addr.sin_addr);
201 if (m_acl.count(client) == 0) {
204 log->error("accept() rejected client at %s", client);