2 * Copyright 2001-2009 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>
34 # include <netinet/in.h>
37 #include <sys/types.h>
38 #include <sys/stat.h> /* for chmod() */
43 using namespace shibsp;
44 using namespace xmltooling;
45 using namespace xercesc;
49 static const XMLCh address[] = UNICODE_LITERAL_7(a,d,d,r,e,s,s);
50 static const XMLCh port[] = UNICODE_LITERAL_4(p,o,r,t);
51 static const XMLCh acl[] = UNICODE_LITERAL_3(a,c,l);
53 class TCPListener : virtual public SocketListener
56 TCPListener(const DOMElement* e);
59 bool create(ShibSocket& s) const;
60 bool bind(ShibSocket& s, bool force=false) const;
61 bool connect(ShibSocket& s) const;
62 bool close(ShibSocket& s) const;
63 bool accept(ShibSocket& listener, ShibSocket& s) const;
65 int send(ShibSocket& s, const char* buf, int len) const {
66 return ::send(s, buf, len, 0);
69 int recv(ShibSocket& s, char* buf, int buflen) const {
70 return ::recv(s, buf, buflen, 0);
74 void setup_tcp_sockaddr(struct sockaddr_in* addr) const;
77 unsigned short m_port;
81 ListenerService* SHIBSP_DLLLOCAL TCPListenerServiceFactory(const DOMElement* const & e)
83 return new TCPListener(e);
87 TCPListener::TCPListener(const DOMElement* e) : SocketListener(e), m_address("127.0.0.1"), m_port(12345)
89 // We're stateless, but we need to load the configuration.
90 const XMLCh* tag=e->getAttributeNS(NULL,address);
96 tag=e->getAttributeNS(NULL,port);
98 m_port=XMLString::parseInt(tag);
103 tag=e->getAttributeNS(NULL,acl);
105 auto_ptr_char temp(tag);
106 string sockacl=temp.get();
107 if (sockacl.length()) {
109 for (unsigned int i=0; i < sockacl.length(); i++) {
110 if (sockacl.at(i)==' ') {
111 m_acl.insert(sockacl.substr(j, i-j));
115 m_acl.insert(sockacl.substr(j, sockacl.length()-j));
119 m_acl.insert("127.0.0.1");
122 void TCPListener::setup_tcp_sockaddr(struct sockaddr_in* addr) const
124 // Split on host:port boundary. Default to port only.
125 memset(addr,0,sizeof(struct sockaddr_in));
126 addr->sin_family=AF_INET;
127 addr->sin_port=htons(m_port);
128 addr->sin_addr.s_addr=inet_addr(m_address.c_str());
131 bool TCPListener::create(ShibSocket& s) const
133 s=socket(AF_INET,SOCK_STREAM,0);
135 if(s==INVALID_SOCKET)
143 bool TCPListener::bind(ShibSocket& s, bool force) const
145 struct sockaddr_in addr;
146 setup_tcp_sockaddr(&addr);
148 // XXX: Do we care about the return value from setsockopt?
150 ::setsockopt(s, SOL_SOCKET, SO_REUSEADDR, (const char*)&opt, sizeof(opt));
153 if (SOCKET_ERROR==::bind(s,(struct sockaddr *)&addr,sizeof(addr)) || SOCKET_ERROR==::listen(s,3)) {
159 if (::bind(s, (struct sockaddr *)&addr, sizeof (addr)) < 0) {
169 bool TCPListener::connect(ShibSocket& s) const
171 struct sockaddr_in addr;
172 setup_tcp_sockaddr(&addr);
174 if(SOCKET_ERROR==::connect(s,(struct sockaddr *)&addr,sizeof(addr)))
177 if (::connect(s, (struct sockaddr*)&addr, sizeof (addr)) < 0)
183 bool TCPListener::close(ShibSocket& s) const
193 bool TCPListener::accept(ShibSocket& listener, ShibSocket& s) const
195 struct sockaddr_in addr;
198 int size=sizeof(addr);
199 s=::accept(listener,(struct sockaddr*)&addr,&size);
200 if(s==INVALID_SOCKET)
202 socklen_t size=sizeof(addr);
203 s=::accept(listener,(struct sockaddr*)&addr,&size);
207 char* client=inet_ntoa(addr.sin_addr);
208 if (m_acl.count(client) == 0) {
211 log->error("accept() rejected client at %s", client);