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.
20 * TCP-based SocketListener implementation
23 #include "SocketListener.h"
26 # include <sys/socket.h>
29 # include <arpa/inet.h>
32 #include <sys/types.h>
33 #include <sys/stat.h> /* for chmod() */
40 using namespace shibboleth;
41 using namespace shibtarget;
42 using namespace log4cpp;
44 static const XMLCh address[] = { chLatin_a, chLatin_d, chLatin_d, chLatin_r, chLatin_e, chLatin_s, chLatin_s, chNull };
45 static const XMLCh port[] = { chLatin_p, chLatin_o, chLatin_r, chLatin_t, chNull };
47 class TCPListener : virtual public SocketListener
50 TCPListener(const DOMElement* e);
53 bool create(ShibSocket& s) const;
54 bool bind(ShibSocket& s, bool force=false) const;
55 bool connect(ShibSocket& s) const;
56 bool close(ShibSocket& s) const;
57 bool accept(ShibSocket& listener, ShibSocket& s) const;
59 int send(ShibSocket& s, const char* buf, int len) const {
60 return ::send(s, buf, len, 0);
63 int recv(ShibSocket& s, char* buf, int buflen) const {
64 return ::recv(s, buf, buflen, 0);
68 void setup_tcp_sockaddr(struct sockaddr_in* addr) const;
71 unsigned short m_port;
75 IPlugIn* TCPListenerFactory(const DOMElement* e)
77 return new TCPListener(e);
80 TCPListener::TCPListener(const DOMElement* e) : SocketListener(e), m_address("127.0.0.1"), m_port(12345)
82 // We're stateless, but we need to load the configuration.
83 const XMLCh* tag=e->getAttributeNS(NULL,address);
89 tag=e->getAttributeNS(NULL,port);
91 m_port=XMLString::parseInt(tag);
96 tag=e->getAttributeNS(NULL,SHIBT_L(acl));
98 auto_ptr_char temp(tag);
99 string sockacl=temp.get();
100 if (sockacl.length()) {
102 for (unsigned int i=0; i < sockacl.length(); i++) {
103 if (sockacl.at(i)==' ') {
104 m_acl.push_back(sockacl.substr(j, i-j));
108 m_acl.push_back(sockacl.substr(j, sockacl.length()-j));
112 m_acl.push_back("127.0.0.1");
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 for (vector<string>::const_iterator i=m_acl.begin(); i!=m_acl.end(); i++) {
207 log->error("accept() rejected client at %s\n",client);