monotone

monotone Mtn Source Tree

Root/netxx/serverbase.cxx

1/*
2 * Copyright (C) 2001-2004 Peter J Jones (pjones@pmade.org)
3 * All Rights Reserved
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 *
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in
13 * the documentation and/or other materials provided with the
14 * distribution.
15 * 3. Neither the name of the Author nor the names of its contributors
16 * may be used to endorse or promote products derived from this software
17 * without specific prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS''
20 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
22 * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR
23 * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
26 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
27 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
28 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
29 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30 * SUCH DAMAGE.
31 */
32
33/** @file
34 * This file contains the implementation of the Netxx::ServerBase class.
35**/
36
37// common header
38#include "common.h"
39
40// Netxx includes
41#include "serverbase.h"
42#include "netxx/address.h"
43#include "netxx/sockopt.h"
44#include "netxx/probeinfo.h"
45#include "socket.h"
46
47// standard includes
48#include <map>
49#include <vector>
50#include <algorithm>
51#include <functional>
52
53//####################################################################
54namespace
55{
56# ifndef WIN32
57struct unlink_functor : public std::unary_function<std::string, void>
58{
59 void operator() (const std::string &file)
60 { unlink(file.c_str()); }
61};
62# endif
63}
64//####################################################################
65Netxx::ServerBase::ServerBase (const Timeout &timeout)
66 : timeout_(timeout), sockets_(0), sockets_size_(0)
67{ /* must not call bind_to from here */ }
68//####################################################################
69Netxx::ServerBase::~ServerBase (void)
70{
71# ifndef WIN32
72if (sockets_ && !files_.empty()) {
73 std::for_each(sockets_, sockets_ + sockets_size_, std::mem_fun_ref(&Socket::close));
74 std::for_each(files_.begin(), files_.end(), unlink_functor());
75}
76# endif
77
78 if (sockets_) delete [] sockets_;
79}
80//####################################################################
81void Netxx::ServerBase::bind_to(const Address &addr, bool stream_server)
82{
83 if (sockets_) throw Exception("bug in Netxx, ServerBase::sockets_ != 0");
84
85 /*
86 * it is safe to allocate this block of memory because the destructor
87 * will free it even if this function dies with an exception.
88 */
89 sockets_size_ = addr.size();
90 sockets_ = new Socket[sockets_size_];
91
92 /*
93 * now that we have an array of sockets we need to walk through each one
94 * and set it up. We will use a temporay socket and make it call
95 * socket() for us. Then we can set the reuse address socket option and
96 * call bind.
97 */
98 Address::const_iterator addr_it=addr.begin(), addr_end=addr.end();
99 for (size_type current_socket=0; addr_it != addr_end; ++addr_it, ++current_socket) {
100const sockaddr *sa = static_cast<const sockaddr*>(addr_it->get_sa());
101size_type sa_size = addr_it->get_sa_size();
102
103Socket::Type stype;
104switch (sa->sa_family) {
105 case AF_INET:
106stype = stream_server ? Socket::TCP : Socket::UDP;
107break;
108
109#ifndef NETXX_NO_INET6
110 case AF_INET6:
111stype = stream_server ? Socket::TCP6 : Socket::UDP6;
112break;
113#endif
114
115#ifndef WIN32
116 case AF_LOCAL:
117stype = stream_server ? Socket::LOCALSTREAM : Socket::LOCALDGRAM;
118break;
119#endif
120
121 default:
122stype = stream_server ? Socket::TCP : Socket::UDP;
123break;
124}
125
126Socket tmp_socket(stype);
127socket_type socketfd = tmp_socket.get_socketfd();
128tmp_socket.swap(sockets_[current_socket]);
129
130SockOpt socket_opt(socketfd);
131socket_opt.set_reuse_address();
132
133#ifndef NETXX_NO_INET6
134if (sa->sa_family == AF_INET6)
135 socket_opt.set_ipv6_listen_for_v6_only();
136#endif
137
138if (bind(socketfd, sa, sa_size) != 0) {
139 std::string error("bind(2) error: ");
140 error += Netxx::str_error(Netxx::get_last_error());
141 throw NetworkException(error);
142}
143
144sockets_map_[socketfd] = &(sockets_[current_socket]);
145pi_.add_socket(socketfd);
146
147#ifndef WIN32
148 /*
149 * check to see if we need to record a filename. we would need
150 * to record a filename for local domain sockets in order to
151 * remove the file when the server is done with it.
152 *
153 * also take this time to set the mode for the socket file to
154 * something sane. this may be a bad assumption here but I think
155 * this is a good value for a domain socket.
156 */
157 if (sa->sa_family == AF_LOCAL) {
158const sockaddr_un *saun = reinterpret_cast<const sockaddr_un*>(sa);
159
160/*
161 * This will make a local domain socket more like a real
162 * socket since anyone with local file system access can
163 * connect to it.
164 */
165chmod(saun->sun_path, 0666);
166
167if (saun->sun_path[0] == '/') {
168 files_.push_back(saun->sun_path);
169} else {
170 char buffer[MAXPATHLEN];
171
172 if (getcwd(buffer, sizeof(buffer))) {
173 std::string fullpath = buffer; fullpath += '/'; fullpath += saun->sun_path;
174files_.push_back(fullpath);
175 } else {
176files_.push_back(saun->sun_path);
177 }
178}
179 }
180#endif
181 }
182
183 probe_.add(*this);
184}
185//####################################################################
186void Netxx::ServerBase::get_socket_list (Socket *&sockets, size_type &size)
187{
188 sockets = sockets_;
189 size = sockets_size_;
190}
191//####################################################################
192Netxx::Socket* Netxx::ServerBase::get_readable_socket (void)
193{
194 Probe::result_type rt = probe_.ready(timeout_, Probe::ready_read);
195 if (rt.first == -1) return 0;
196 return sockets_map_[rt.first];
197}
198//####################################################################
199void Netxx::ServerBase::set_timeout (const Timeout &timeout)
200{
201 timeout_ = timeout;
202}
203//####################################################################
204const Netxx::Timeout& Netxx::ServerBase::get_timeout (void) const
205{
206 return timeout_;
207}
208//####################################################################
209const Netxx::ProbeInfo* Netxx::ServerBase::get_probe_info (void) const
210{
211 return &pi_;
212}
213//####################################################################
214bool Netxx::ServerBase::has_socket (socket_type socketfd) const
215{
216 return sockets_map_.find(socketfd) != sockets_map_.end();
217}
218//####################################################################

Archive Download this file

Branches

Tags

Quick Links:     www.monotone.ca    -     Downloads    -     Documentation    -     Wiki    -     Code Forge    -     Build Status