Replaced RPC remoting with plain sockets and length-prefixed XML.
[shibboleth/cpp-sp.git] / shib-target / UnixListener.cpp
1 /*\r
2  *  Copyright 2001-2005 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 "RPCListener.h"\r
24 \r
25 #ifdef HAVE_UNISTD_H\r
26 # include <sys/socket.h>\r
27 # include <sys/un.h>\r
28 # include <unistd.h>\r
29 # include <arpa/inet.h>\r
30 #endif\r
31 \r
32 #include <sys/types.h>\r
33 #include <sys/stat.h>           /* for chmod() */\r
34 #include <stdio.h>\r
35 #include <stdlib.h>\r
36 #include <errno.h>\r
37 \r
38 using namespace std;\r
39 using namespace saml;\r
40 using namespace shibboleth;\r
41 using namespace shibtarget;\r
42 using namespace log4cpp;\r
43 \r
44 static const XMLCh address[] = { chLatin_a, chLatin_d, chLatin_d, chLatin_r, chLatin_e, chLatin_s, chLatin_s, chNull };\r
45 \r
46 class UnixListener : virtual public SocketListener\r
47 {\r
48 public:\r
49     UnixListener(const DOMElement* e);\r
50     ~UnixListener() {if (m_bound) unlink(m_address.c_str());}\r
51 \r
52     bool create(ShibSocket& s) const;\r
53     bool bind(ShibSocket& s, bool force=false) const;\r
54     bool connect(ShibSocket& s) const;\r
55     bool close(ShibSocket& s) const;\r
56     bool accept(ShibSocket& listener, ShibSocket& s) const;\r
57 \r
58     int send(ShibSocket& s, const char* buf, int len) const {\r
59         return ::send(s, buf, len, 0);\r
60     }\r
61     \r
62     int recv(ShibSocket& s, char* buf, int buflen) const {\r
63         return ::recv(s, buf, buflen, 0);\r
64     }\r
65     \r
66 private:\r
67     string m_address;\r
68     mutable bool m_bound;\r
69 };\r
70 \r
71 IPlugIn* UnixListenerFactory(const DOMElement* e)\r
72 {\r
73     return new UnixListener(e);\r
74 }\r
75 \r
76 UnixListener::UnixListener(const DOMElement* e) : RPCListener(e), m_address("/var/run/shar-socket"), m_bound(false)\r
77 {\r
78     // We're stateless, but we need to load the configuration.\r
79     const XMLCh* tag=e->getAttributeNS(NULL,address);\r
80     if (tag && *tag) {\r
81         auto_ptr_char a(tag);\r
82         m_address=a.get();\r
83     }\r
84 }\r
85 \r
86 #ifndef UNIX_PATH_MAX\r
87 #define UNIX_PATH_MAX 100\r
88 #endif\r
89 \r
90 bool UnixListener::create(ShibSocket& sock) const\r
91 {\r
92     sock = socket(PF_UNIX, SOCK_STREAM, 0);\r
93     if (sock < 0)\r
94         return log_error();\r
95     return true;\r
96 }\r
97 \r
98 bool UnixListener::bind(ShibSocket& s, bool force) const\r
99 {\r
100     struct sockaddr_un addr;\r
101     memset(&addr, 0, sizeof (addr));\r
102     addr.sun_family = AF_UNIX;\r
103     strncpy(addr.sun_path, m_address.c_str(), UNIX_PATH_MAX);\r
104 \r
105     if (force)\r
106         unlink(m_address.c_str());\r
107 \r
108     if (::bind(s, (struct sockaddr *)&addr, sizeof (addr)) < 0) {\r
109         log_error();\r
110         close(s);\r
111         return false;\r
112     }\r
113 \r
114     // Make sure that only the creator can read -- we don't want just\r
115     // anyone connecting, do we?\r
116     if (chmod(m_address.c_str(),0777) < 0) {\r
117         log_error();\r
118         close(s);\r
119         unlink(m_address.c_str());\r
120         return false;\r
121     }\r
122 \r
123     listen(s, 3);\r
124     return m_bound=true;\r
125 }\r
126 \r
127 bool UnixListener::connect(ShibSocket& s) const\r
128 {\r
129     struct sockaddr_un addr;\r
130     memset(&addr, 0, sizeof (addr));\r
131     addr.sun_family = AF_UNIX;\r
132     strncpy(addr.sun_path, m_address.c_str(), UNIX_PATH_MAX);\r
133 \r
134     if (::connect(s, (struct sockaddr *)&addr, sizeof (addr)) < 0)\r
135         return log_error();\r
136     return true;\r
137 }\r
138 \r
139 bool UnixListener::close(ShibSocket& s) const\r
140 {\r
141     ::close(s);\r
142     return true;\r
143 }\r
144 \r
145 bool UnixListener::accept(ShibSocket& listener, ShibSocket& s) const\r
146 {\r
147     s=::accept(listener,NULL,NULL);\r
148     if (s < 0)\r
149         return log_error();\r
150     return true;\r
151 }\r
152 \r
153 CLIENT* UnixListener::getClientHandle(ShibSocket& s, u_long program, u_long version) const\r
154 {\r
155     struct sockaddr_in sin;\r
156     memset (&sin, 0, sizeof (sin));\r
157     sin.sin_port = 1;\r
158     return clnttcp_create(&sin, program, version, &s, 0, 0);\r
159 }\r