monotone

monotone Mtn Source Tree

Root/netxx/socket.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 for the Netxx::Socket class along
35 * with some helper functions.
36**/
37
38// common header
39#include "common.h"
40
41// Netxx includes
42#include "socket.h"
43#include "netxx/timeout.h"
44
45// standard includes
46#include <algorithm>
47#include <string>
48#include <cstring>
49#include <cstdio>
50
51//####################################################################
52namespace
53{
54 const Netxx::socket_type const_invalid_socket = -1;
55 void get_domain_and_type (Netxx::Socket::Type stype, int &domain, int &type);
56}
57//####################################################################
58Netxx::Socket::Socket (void)
59 : socketfd_(const_invalid_socket), probe_ready_(false), type_ready_(false)
60{
61# if defined(WIN32)
62WSADATA wsdata;
63
64if (WSAStartup(MAKEWORD(2,2), &wsdata) != 0) {
65 throw Exception("failed to load WinSock");
66}
67# endif
68}
69//####################################################################
70Netxx::Socket::Socket (Type type)
71 : socketfd_(const_invalid_socket), probe_ready_(false), type_ready_(true), type_(type)
72{
73# if defined(WIN32)
74WSADATA wsdata;
75
76if (WSAStartup(MAKEWORD(2,2), &wsdata) != 0) {
77 throw Exception("failed to load WinSock");
78}
79# endif
80
81 int socket_domain=0;
82 socket_type socket_type=0, socket_fd=0;
83
84 get_domain_and_type(type, socket_domain, socket_type);
85
86 if ( (socket_fd = socket(socket_domain, socket_type, 0)) < 0) {
87std::string error("failure from socket(2): ");
88error += str_error(get_last_error());
89throw Exception(error);
90 }
91
92 socketfd_ = socket_fd;
93}
94//####################################################################
95Netxx::Socket::Socket (int socketfd)
96 : socketfd_(socketfd), probe_ready_(false), type_ready_(false)
97{
98# if defined(WIN32)
99WSADATA wsdata;
100
101if (WSAStartup(MAKEWORD(2,2), &wsdata) != 0) {
102 throw Exception("failed to load WinSock");
103}
104# endif
105}
106//####################################################################
107Netxx::Socket::Socket (const Socket &other)
108 : probe_ready_(false), type_ready_(other.type_ready_), type_(other.type_)
109{
110 if (other.socketfd_ != const_invalid_socket) {
111socket_type dup_socket;
112
113#if defined(WIN32)
114 WSADATA wsdata;
115
116 if (WSAStartup(MAKEWORD(2,2), &wsdata) != 0)
117throw Exception("failed to load WinSock");
118
119 WSAPROTOCOL_INFO proto_info;
120 std::memset(&proto_info, 0, sizeof(proto_info));
121
122 if (WSADuplicateSocket(other.socketfd_, GetCurrentProcessId(), &proto_info)) {
123throw Exception("failed to duplicate socket");
124 }
125
126 if ( (dup_socket = WSASocket(FROM_PROTOCOL_INFO, FROM_PROTOCOL_INFO,
127 FROM_PROTOCOL_INFO, &proto_info, 0, WSA_FLAG_OVERLAPPED)) == INVALID_SOCKET)
128 {
129throw Exception("failed to init duplicated socket");
130 }
131#else
132 dup_socket = dup(other.socketfd_);
133
134 if (dup_socket < 0) {
135std::string error("dup(2) call failed: ");
136error += str_error(get_last_error());
137throw Exception(error);
138 }
139#endif
140
141socketfd_ = dup_socket;
142 } else {
143socketfd_ = const_invalid_socket;
144 }
145}
146//####################################################################
147Netxx::Socket& Netxx::Socket::operator= (const Socket &other)
148{
149 Socket tmp(other); swap(tmp);
150 return *this;
151}
152//####################################################################
153void Netxx::Socket::swap (Socket &other)
154{
155 std::swap(socketfd_, other.socketfd_);
156 std::swap(type_ready_, other.type_ready_);
157 std::swap(type_, other.type_);
158
159 probe_ready_ = other.probe_ready_ = false;
160 probe_.clear(); other.probe_.clear();
161}
162//####################################################################
163Netxx::Socket::~Socket (void)
164{
165 close();
166
167# if defined(WIN32)
168WSACleanup();
169# endif
170}
171//####################################################################
172Netxx::signed_size_type Netxx::Socket::write (const void *buffer, size_type length, const Timeout &timeout)
173{
174 const char *buffer_ptr = static_cast<const char*>(buffer);
175 signed_size_type rc, bytes_written=0;
176
177 while (length) {
178if (timeout && !writable(timeout)) return -1;
179
180if ( (rc = send(socketfd_, buffer_ptr, length, 0)) < 0) {
181 error_type error_code = get_last_error();
182 if (error_code == EWOULDBLOCK) error_code = EAGAIN;
183
184 switch (error_code) {
185case EPIPE:
186case ECONNRESET:
187 return 0;
188
189case EINTR:
190 continue;
191
192case EAGAIN:
193 return -1;
194
195#if defined(WIN32)
196case WSAENETRESET:
197case WSAESHUTDOWN:
198case WSAEHOSTUNREACH:
199case WSAECONNABORTED:
200case WSAETIMEDOUT:
201 return 0;
202#endif
203
204default:
205{
206 std::string error("send failed: ");
207 error += str_error(error_code);
208 throw Exception(error);
209}
210 }
211}
212
213buffer_ptr += rc;
214bytes_written += rc;
215length -= rc;
216 }
217
218 return bytes_written;
219}
220//####################################################################
221Netxx::signed_size_type Netxx::Socket::read (void *buffer, size_type length, const Timeout &timeout)
222{
223 signed_size_type rc;
224
225# if defined(WIN32)
226char *buffer_ptr = static_cast<char*>(buffer);
227# else
228void *buffer_ptr(buffer);
229# endif
230
231 for (;;) {
232if (timeout && !readable(timeout)) return -1;
233
234if ( (rc = recv(socketfd_, buffer_ptr, length, 0)) < 0) {
235 error_type error_code = get_last_error();
236 if (error_code == EWOULDBLOCK) error_code = EAGAIN;
237
238 switch (error_code) {
239case ECONNRESET:
240 return 0;
241
242case EINTR:
243 continue;
244
245case EAGAIN:
246 return -1;
247
248#if defined(WIN32)
249
250case WSAEMSGSIZE:
251 return length;
252
253case WSAENETRESET:
254case WSAESHUTDOWN:
255case WSAECONNABORTED:
256case WSAETIMEDOUT: // FIXME should this be return -1?
257 return 0;
258
259#endif
260
261default:
262{
263 std::string error("recv failure: ");
264 error += str_error(error_code);
265 throw Exception(error);
266}
267 }
268}
269
270break;
271 }
272
273 return rc;
274}
275//####################################################################
276bool Netxx::Socket::readable (const Timeout &timeout)
277{
278 if (!probe_ready_) {
279probe_.add(socketfd_);
280probe_ready_ = true;
281 }
282
283 Probe_impl::probe_type pt = probe_.probe(timeout, Probe::ready_read);
284 if (pt.empty()) return false;
285 return true;
286}
287//####################################################################
288bool Netxx::Socket::writable (const Timeout &timeout)
289{
290 if (!probe_ready_) {
291probe_.add(socketfd_);
292probe_ready_ = true;
293 }
294
295 Probe_impl::probe_type pt = probe_.probe(timeout, Probe::ready_write);
296 if (pt.empty()) return false;
297 return true;
298}
299//####################################################################
300bool Netxx::Socket::readable_or_writable (const Timeout &timeout)
301{
302 if (!probe_ready_) {
303probe_.add(socketfd_);
304probe_ready_ = true;
305 }
306
307 Probe_impl::probe_type pt = probe_.probe(timeout, Probe::ready_read|Probe::ready_write);
308 if (pt.empty()) return false;
309 return true;
310}
311//####################################################################
312void Netxx::Socket::close (void)
313{
314 if (socketfd_ != const_invalid_socket) {
315#if defined(WIN32)
316 closesocket(socketfd_);
317#else
318 ::close(socketfd_);
319#endif
320
321socketfd_ = const_invalid_socket;
322 }
323}
324//####################################################################
325void Netxx::Socket::release (void)
326{
327 socketfd_ = const_invalid_socket;
328}
329//####################################################################
330Netxx::Socket::Type Netxx::Socket::get_type (void) const
331{
332 if (!type_ready_) throw Exception("Netxx bug: Socket::get_type called when !type_ready_");
333 return type_;
334}
335//####################################################################
336int Netxx::Socket::get_socketfd (void) const
337{
338 return socketfd_;
339}
340//####################################################################
341void Netxx::Socket::set_socketfd (socket_type socketfd)
342{
343 close();
344 probe_ready_ = false;
345 socketfd_ = socketfd;
346 probe_.clear();
347}
348//####################################################################
349bool Netxx::Socket::operator! (void) const
350{
351 return socketfd_ == const_invalid_socket;
352}
353//####################################################################
354bool Netxx::Socket::operator< (const Socket &other) const
355{
356 return socketfd_ < other.socketfd_;
357}
358//####################################################################
359bool Netxx::Socket::operator< (socket_type socketfd) const
360{
361 return socketfd_ < socketfd;
362}
363//####################################################################
364bool Netxx::operator== (const Netxx::Socket &first, const Netxx::Socket &second)
365{
366 return first.get_socketfd() == second.get_socketfd();
367}
368//####################################################################
369bool Netxx::operator!= (const Netxx::Socket &first, const Netxx::Socket &second)
370{
371 return !(first == second);
372}
373//####################################################################
374namespace
375{
376 //####################################################################
377 void get_domain_and_type (Netxx::Socket::Type stype, int &domain, int &type)
378 {
379switch (stype) {
380 case Netxx::Socket::TCP:
381domain = PF_INET;
382type= SOCK_STREAM;
383break;
384
385 case Netxx::Socket::UDP:
386domain= PF_INET;
387type= SOCK_DGRAM;
388break;
389
390# ifndef NETXX_NO_INET6
391 case Netxx::Socket::TCP6:
392domain= PF_INET6;
393type= SOCK_STREAM;
394break;
395
396 case Netxx::Socket::UDP6:
397domain= PF_INET6;
398type= SOCK_DGRAM;
399break;
400# endif
401# ifndef WIN32
402 case Netxx::Socket::LOCALSTREAM:
403domain= PF_LOCAL;
404type= SOCK_STREAM;
405break;
406
407 case Netxx::Socket::LOCALDGRAM:
408domain= PF_LOCAL;
409type= SOCK_DGRAM;
410break;
411# endif
412 default:
413domain = PF_INET;
414type= SOCK_STREAM;
415break;
416}
417 }
418 //####################################################################
419} // end anonymous namespace

Archive Download this file

Branches

Tags

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