2 * Copyright 2001-2007 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>
30 # include <sys/socket.h>
33 # include <arpa/inet.h>
36 #include <sys/types.h>
37 #include <sys/stat.h> /* for chmod() */
42 using namespace shibsp;
43 using namespace xmltooling;
44 using namespace xercesc;
48 static const XMLCh address[] = UNICODE_LITERAL_7(a,d,d,r,e,s,s);
49 static const XMLCh port[] = UNICODE_LITERAL_4(p,o,r,t);
50 static const XMLCh acl[] = UNICODE_LITERAL_3(a,c,l);
52 class TCPListener : virtual public SocketListener
55 TCPListener(const DOMElement* e);
58 bool create(ShibSocket& s) const;
59 bool bind(ShibSocket& s, bool force=false) const;
60 bool connect(ShibSocket& s) const;
61 bool close(ShibSocket& s) const;
62 bool accept(ShibSocket& listener, ShibSocket& s) const;
64 int send(ShibSocket& s, const char* buf, int len) const {
65 return ::send(s, buf, len, 0);
68 int recv(ShibSocket& s, char* buf, int buflen) const {
69 return ::recv(s, buf, buflen, 0);
73 void setup_tcp_sockaddr(struct sockaddr_in* addr) const;
76 unsigned short m_port;
80 ListenerService* SHIBSP_DLLLOCAL TCPListenerServiceFactory(const DOMElement* const & e)
82 return new TCPListener(e);
86 TCPListener::TCPListener(const DOMElement* e) : SocketListener(e), m_address("127.0.0.1"), m_port(12345)
88 // We're stateless, but we need to load the configuration.
89 const XMLCh* tag=e->getAttributeNS(NULL,address);
95 tag=e->getAttributeNS(NULL,port);
97 m_port=XMLString::parseInt(tag);
102 tag=e->getAttributeNS(NULL,acl);
104 auto_ptr_char temp(tag);
105 string sockacl=temp.get();
106 if (sockacl.length()) {
108 for (unsigned int i=0; i < sockacl.length(); i++) {
109 if (sockacl.at(i)==' ') {
110 m_acl.push_back(sockacl.substr(j, i-j));
114 m_acl.push_back(sockacl.substr(j, sockacl.length()-j));
118 m_acl.push_back("127.0.0.1");
121 void TCPListener::setup_tcp_sockaddr(struct sockaddr_in* addr) const
123 // Split on host:port boundary. Default to port only.
124 memset(addr,0,sizeof(struct sockaddr_in));
125 addr->sin_family=AF_INET;
126 addr->sin_port=htons(m_port);
127 addr->sin_addr.s_addr=inet_addr(m_address.c_str());
130 bool TCPListener::create(ShibSocket& s) const
132 s=socket(AF_INET,SOCK_STREAM,0);
134 if(s==INVALID_SOCKET)
142 bool TCPListener::bind(ShibSocket& s, bool force) const
144 struct sockaddr_in addr;
145 setup_tcp_sockaddr(&addr);
147 // XXX: Do we care about the return value from setsockopt?
149 ::setsockopt(s, SOL_SOCKET, SO_REUSEADDR, (const char*)&opt, sizeof(opt));
152 if (SOCKET_ERROR==::bind(s,(struct sockaddr *)&addr,sizeof(addr)) || SOCKET_ERROR==::listen(s,3)) {
158 if (::bind(s, (struct sockaddr *)&addr, sizeof (addr)) < 0) {
168 bool TCPListener::connect(ShibSocket& s) const
170 struct sockaddr_in addr;
171 setup_tcp_sockaddr(&addr);
173 if(SOCKET_ERROR==::connect(s,(struct sockaddr *)&addr,sizeof(addr)))
176 if (::connect(s, (struct sockaddr*)&addr, sizeof (addr)) < 0)
182 bool TCPListener::close(ShibSocket& s) const
192 bool TCPListener::accept(ShibSocket& listener, ShibSocket& s) const
194 struct sockaddr_in addr;
197 int size=sizeof(addr);
198 s=::accept(listener,(struct sockaddr*)&addr,&size);
199 if(s==INVALID_SOCKET)
201 socklen_t size=sizeof(addr);
202 s=::accept(listener,(struct sockaddr*)&addr,&size);
206 char* client=inet_ntoa(addr.sin_addr);
207 for (vector<string>::const_iterator i=m_acl.begin(); i!=m_acl.end(); i++) {
213 log->error("accept() rejected client at %s\n",client);