d9a9b8bdaf9047984429a69ba5d95dd59f54c397
[shibboleth/sp.git] / shibsp / remoting / impl / UnixListener.cpp
1 /*\r
2  *  Copyright 2001-2007 Internet2\r
3  * \r
4  * Licensed under the Apache License, Version 2.0 (the "License");\r
5  * you may not use this file except in compliance with the License.\r
6  * You may obtain a copy of the License at\r
7  *\r
8  *     http://www.apache.org/licenses/LICENSE-2.0\r
9  *\r
10  * Unless required by applicable law or agreed to in writing, software\r
11  * distributed under the License is distributed on an "AS IS" BASIS,\r
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
13  * See the License for the specific language governing permissions and\r
14  * limitations under the License.\r
15  */\r
16 \r
17 /**\r
18  * UnixListener.cpp\r
19  * \r
20  * Unix Domain-based SocketListener implementation\r
21  */\r
22 \r
23 #include "internal.h"\r
24 #include "remoting/impl/SocketListener.h"\r
25 \r
26 #include <xercesc/util/XMLUniDefs.hpp>\r
27 #include <xmltooling/unicode.h>\r
28 \r
29 #ifdef HAVE_UNISTD_H\r
30 # include <sys/socket.h>\r
31 # include <sys/un.h>\r
32 # include <unistd.h>\r
33 # include <arpa/inet.h>\r
34 #endif\r
35 \r
36 #include <sys/types.h>\r
37 #include <sys/stat.h>           /* for chmod() */\r
38 #include <stdio.h>\r
39 #include <stdlib.h>\r
40 #include <errno.h>\r
41 \r
42 using namespace shibsp;\r
43 using namespace xmltooling;\r
44 using namespace xercesc;\r
45 using namespace std;\r
46 \r
47 \r
48 namespace shibsp {\r
49     static const XMLCh address[] = UNICODE_LITERAL_7(a,d,d,r,e,s,s);\r
50 \r
51     class UnixListener : virtual public SocketListener\r
52     {\r
53     public:\r
54         UnixListener(const DOMElement* e);\r
55         ~UnixListener() {if (m_bound) unlink(m_address.c_str());}\r
56 \r
57         bool create(ShibSocket& s) const;\r
58         bool bind(ShibSocket& s, bool force=false) const;\r
59         bool connect(ShibSocket& s) const;\r
60         bool close(ShibSocket& s) const;\r
61         bool accept(ShibSocket& listener, ShibSocket& s) const;\r
62 \r
63         int send(ShibSocket& s, const char* buf, int len) const {\r
64             return ::send(s, buf, len, 0);\r
65         }\r
66         \r
67         int recv(ShibSocket& s, char* buf, int buflen) const {\r
68             return ::recv(s, buf, buflen, 0);\r
69         }\r
70         \r
71     private:\r
72         string m_address;\r
73         mutable bool m_bound;\r
74     };\r
75 \r
76     ListenerService* SHIBSP_DLLLOCAL UnixListenerServiceFactory(const DOMElement* const & e)\r
77     {\r
78         return new UnixListener(e);\r
79     }\r
80 };\r
81 \r
82 UnixListener::UnixListener(const DOMElement* e) : SocketListener(e), m_address("/var/run/shar-socket"), m_bound(false)\r
83 {\r
84     // We're stateless, but we need to load the configuration.\r
85     const XMLCh* tag=e->getAttributeNS(NULL,address);\r
86     if (tag && *tag) {\r
87         auto_ptr_char a(tag);\r
88         m_address=a.get();\r
89     }\r
90 }\r
91 \r
92 #ifndef UNIX_PATH_MAX\r
93 #define UNIX_PATH_MAX 100\r
94 #endif\r
95 \r
96 bool UnixListener::create(ShibSocket& sock) const\r
97 {\r
98     sock = socket(PF_UNIX, SOCK_STREAM, 0);\r
99     if (sock < 0)\r
100         return log_error();\r
101     return true;\r
102 }\r
103 \r
104 bool UnixListener::bind(ShibSocket& s, bool force) const\r
105 {\r
106     struct sockaddr_un addr;\r
107     memset(&addr, 0, sizeof (addr));\r
108     addr.sun_family = AF_UNIX;\r
109     strncpy(addr.sun_path, m_address.c_str(), UNIX_PATH_MAX);\r
110 \r
111     if (force)\r
112         unlink(m_address.c_str());\r
113 \r
114     if (::bind(s, (struct sockaddr *)&addr, sizeof (addr)) < 0) {\r
115         log_error();\r
116         close(s);\r
117         return false;\r
118     }\r
119 \r
120     // Make sure that only the creator can read -- we don't want just\r
121     // anyone connecting, do we?\r
122     if (chmod(m_address.c_str(),0777) < 0) {\r
123         log_error();\r
124         close(s);\r
125         unlink(m_address.c_str());\r
126         return false;\r
127     }\r
128 \r
129     listen(s, 3);\r
130     return m_bound=true;\r
131 }\r
132 \r
133 bool UnixListener::connect(ShibSocket& s) const\r
134 {\r
135     struct sockaddr_un addr;\r
136     memset(&addr, 0, sizeof (addr));\r
137     addr.sun_family = AF_UNIX;\r
138     strncpy(addr.sun_path, m_address.c_str(), UNIX_PATH_MAX);\r
139 \r
140     if (::connect(s, (struct sockaddr *)&addr, sizeof (addr)) < 0)\r
141         return log_error();\r
142     return true;\r
143 }\r
144 \r
145 bool UnixListener::close(ShibSocket& s) const\r
146 {\r
147     ::close(s);\r
148     return true;\r
149 }\r
150 \r
151 bool UnixListener::accept(ShibSocket& listener, ShibSocket& s) const\r
152 {\r
153     s=::accept(listener,NULL,NULL);\r
154     if (s < 0)\r
155         return log_error();\r
156     return true;\r
157 }\r