2 * Licensed to the University Corporation for Advanced Internet
3 * Development, Inc. (UCAID) under one or more contributor license
4 * agreements. See the NOTICE file distributed with this work for
5 * additional information regarding copyright ownership.
7 * UCAID licenses this file to you under the Apache License,
8 * Version 2.0 (the "License"); you may not use this file except
9 * in compliance with the License. You may obtain a copy of the
12 * http://www.apache.org/licenses/LICENSE-2.0
14 * Unless required by applicable law or agreed to in writing,
15 * software distributed under the License is distributed on an
16 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
17 * either express or implied. See the License for the specific
18 * language governing permissions and limitations under the License.
24 * TCP-based SocketListener implementation.
28 #include "remoting/impl/SocketListener.h"
30 #include <xercesc/util/XMLUniDefs.hpp>
31 #include <xmltooling/unicode.h>
32 #include <xmltooling/util/XMLHelper.h>
35 # include <sys/socket.h>
38 # include <arpa/inet.h>
39 # include <netinet/in.h>
42 #include <sys/types.h>
43 #include <sys/stat.h> /* for chmod() */
48 using namespace shibsp;
49 using namespace xmltooling;
50 using namespace xercesc;
54 class TCPListener : virtual public SocketListener
57 TCPListener(const DOMElement* e);
60 bool create(ShibSocket& s) const;
61 bool bind(ShibSocket& s, bool force=false) const;
62 bool connect(ShibSocket& s) const;
63 bool close(ShibSocket& s) const;
64 bool accept(ShibSocket& listener, ShibSocket& s) const;
66 int send(ShibSocket& s, const char* buf, int len) const {
67 return ::send(s, buf, len, 0);
70 int recv(ShibSocket& s, char* buf, int buflen) const {
71 return ::recv(s, buf, buflen, 0);
75 void setup_tcp_sockaddr(struct sockaddr_in* addr) const;
78 unsigned short m_port;
82 ListenerService* SHIBSP_DLLLOCAL TCPListenerServiceFactory(const DOMElement* const & e)
84 return new TCPListener(e);
87 static const XMLCh address[] = UNICODE_LITERAL_7(a,d,d,r,e,s,s);
88 static const XMLCh port[] = UNICODE_LITERAL_4(p,o,r,t);
89 static const XMLCh acl[] = UNICODE_LITERAL_3(a,c,l);
92 TCPListener::TCPListener(const DOMElement* e)
94 m_address(XMLHelper::getAttrString(e, getenv("SHIBSP_LISTENER_ADDRESS"), address)),
95 m_port(XMLHelper::getAttrInt(e, 0, port))
97 if (m_address.empty())
98 m_address = "127.0.0.1";
101 const char* p = getenv("SHIBSP_LISTENER_PORT");
109 string sockacl = XMLHelper::getAttrString(e, "127.0.0.1", acl);
110 for (unsigned int i = 0; i < sockacl.length(); i++) {
111 if (sockacl.at(i) == ' ') {
112 m_acl.insert(sockacl.substr(j, i-j));
116 m_acl.insert(sockacl.substr(j, sockacl.length()-j));
119 void TCPListener::setup_tcp_sockaddr(struct sockaddr_in* addr) const
121 // Split on host:port boundary. Default to port only.
122 memset(addr,0,sizeof(struct sockaddr_in));
123 addr->sin_family=AF_INET;
124 addr->sin_port=htons(m_port);
125 addr->sin_addr.s_addr=inet_addr(m_address.c_str());
128 bool TCPListener::create(ShibSocket& s) const
130 s=socket(AF_INET,SOCK_STREAM,0);
132 if(s==INVALID_SOCKET)
140 bool TCPListener::bind(ShibSocket& s, bool force) const
142 struct sockaddr_in addr;
143 setup_tcp_sockaddr(&addr);
145 // XXX: Do we care about the return value from setsockopt?
147 ::setsockopt(s, SOL_SOCKET, SO_REUSEADDR, (const char*)&opt, sizeof(opt));
150 if (SOCKET_ERROR==::bind(s,(struct sockaddr *)&addr,sizeof(addr)) || SOCKET_ERROR==::listen(s,3)) {
156 if (::bind(s, (struct sockaddr *)&addr, sizeof (addr)) < 0) {
166 bool TCPListener::connect(ShibSocket& s) const
168 struct sockaddr_in addr;
169 setup_tcp_sockaddr(&addr);
171 if(SOCKET_ERROR==::connect(s,(struct sockaddr *)&addr,sizeof(addr)))
174 if (::connect(s, (struct sockaddr*)&addr, sizeof (addr)) < 0)
180 bool TCPListener::close(ShibSocket& s) const
190 bool TCPListener::accept(ShibSocket& listener, ShibSocket& s) const
192 struct sockaddr_in addr;
195 int size=sizeof(addr);
196 s=::accept(listener,(struct sockaddr*)&addr,&size);
197 if(s==INVALID_SOCKET)
199 socklen_t size=sizeof(addr);
200 s=::accept(listener,(struct sockaddr*)&addr,&size);
204 char* client=inet_ntoa(addr.sin_addr);
205 if (m_acl.count(client) == 0) {
208 log->error("accept() rejected client at %s", client);