blob: 45e3e7a5360edacc3e38f86cfb6b370058c2ce1b [file] [log] [blame]
Emeric Vigier2f625822012-08-06 11:09:52 -04001// Copyright (C) 1999-2005 Open Source Telecom Corporation.
2// Copyright (C) 2006-2010 David Sugar, Tycho Softworks.
3//
4// This program is free software; you can redistribute it and/or modify
5// it under the terms of the GNU General Public License as published by
6// the Free Software Foundation; either version 2 of the License, or
7// (at your option) any later version.
8//
9// This program is distributed in the hope that it will be useful,
10// but WITHOUT ANY WARRANTY; without even the implied warranty of
11// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12// GNU General Public License for more details.
13//
14// You should have received a copy of the GNU General Public License
15// along with this program; if not, write to the Free Software
16// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
17//
18// As a special exception, you may use this file as part of a free software
19// library without restriction. Specifically, if other files instantiate
20// templates or use macros or inline functions from this file, or you compile
21// this file and link it with other files to produce an executable, this
22// file does not by itself cause the resulting executable to be covered by
23// the GNU General Public License. This exception does not however
24// invalidate any other reasons why the executable file might be covered by
25// the GNU General Public License.
26//
27// This exception applies only to the code released under the name GNU
28// Common C++. If you copy code from other releases into a copy of GNU
29// Common C++, as the General Public License permits, the exception does
30// not apply to the code that you add in this way. To avoid misleading
31// anyone as to the status of such modified files, you must delete
32// this exception notice from them.
33//
34// If you write modifications of your own for GNU Common C++, it is your choice
35// whether to permit this exception to apply to your modifications.
36// If you do not wish that, delete this exception notice.
37//
38
39#include <cc++/config.h>
40#include <cc++/export.h>
41#include <cc++/thread.h>
42#include <cc++/address.h>
43#include <cc++/socket.h>
44#include "private.h"
45
46#ifdef WIN32
47#include <fcntl.h>
48#endif
49#include <cerrno>
50
51#ifndef INADDR_LOOPBACK
52#define INADDR_LOOPBACK (unsigned long)0x7f000001
53#endif
54
55#ifdef CCXX_NAMESPACES
56namespace ost {
57#endif
58
59UDPTransmit::UDPTransmit(const IPV4Address &ia, tpport_t port) :
60UDPSocket(ia, port)
61{
62 disconnect(); // assure not started live
63 shutdown(so, 0);
64 receiveBuffer(0);
65}
66
67#ifdef CCXX_IPV6
68UDPTransmit::UDPTransmit(const IPV6Address &ia, tpport_t port) :
69UDPSocket(ia, port)
70{
71 disconnect(); // assure not started live
72 shutdown(so, 0);
73 receiveBuffer(0);
74}
75#endif
76
77UDPTransmit::UDPTransmit(Family family) : UDPSocket(family)
78{
79 disconnect();
80 shutdown(so, 0);
81 receiveBuffer(0);
82}
83
84Socket::Error UDPTransmit::cConnect(const IPV4Address &ia, tpport_t port)
85{
86 int len = sizeof(peer.ipv4);
87
88 peer.ipv4.sin_family = AF_INET;
89 peer.ipv4.sin_addr = getaddress(ia);
90 peer.ipv4.sin_port = htons(port);
91 // Win32 will crash if you try to connect to INADDR_ANY.
92 if ( INADDR_ANY == peer.ipv4.sin_addr.s_addr )
93 peer.ipv4.sin_addr.s_addr = INADDR_LOOPBACK;
94 if(::connect(so, (sockaddr *)&peer.ipv4, len))
95 return connectError();
96 return errSuccess;
97}
98
99
100#ifdef CCXX_IPV6
101
102Socket::Error UDPTransmit::connect(const IPV6Address &ia, tpport_t port)
103{
104 int len = sizeof(peer.ipv6);
105
106 peer.ipv6.sin6_family = AF_INET6;
107 peer.ipv6.sin6_addr = getaddress(ia);
108 peer.ipv6.sin6_port = htons(port);
109 // Win32 will crash if you try to connect to INADDR_ANY.
110 if(!memcmp(&peer.ipv6.sin6_addr, &in6addr_any, sizeof(in6addr_any)))
111 memcpy(&peer.ipv6.sin6_addr, &in6addr_loopback,
112 sizeof(in6addr_loopback));
113 if(::connect(so, (struct sockaddr *)&peer.ipv6, len))
114 return connectError();
115 return errSuccess;
116}
117#endif
118
119Socket::Error UDPTransmit::connect(const IPV4Host &ia, tpport_t port)
120{
121 if(isBroadcast())
122 setBroadcast(false);
123
124 return cConnect((IPV4Address)ia,port);
125}
126
127Socket::Error UDPTransmit::connect(const IPV4Broadcast &subnet, tpport_t port)
128{
129 if(!isBroadcast())
130 setBroadcast(true);
131
132 return cConnect((IPV4Address)subnet,port);
133}
134
135Socket::Error UDPTransmit::connect(const IPV4Multicast &group, tpport_t port)
136{
137 Error err;
138 if(!( err = UDPSocket::setMulticast(true) ))
139 return err;
140
141 return cConnect((IPV4Address)group,port);
142}
143
144#ifdef CCXX_IPV6
145Socket::Error UDPTransmit::connect(const IPV6Multicast &group, tpport_t port)
146{
147 Error error;
148 if(!( error = UDPSocket::setMulticast(true) ))
149 return error;
150
151 return connect((IPV6Address)group,port);
152}
153#endif
154
155UDPReceive::UDPReceive(const IPV4Address &ia, tpport_t port) :
156UDPSocket(ia, port)
157{
158 shutdown(so, 1);
159 sendBuffer(0);
160}
161
162#ifdef CCXX_IPV6
163UDPReceive::UDPReceive(const IPV6Address &ia, tpport_t port) :
164UDPSocket(ia, port)
165{
166 shutdown(so, 1);
167 sendBuffer(0);
168}
169#endif
170
171Socket::Error UDPReceive::connect(const IPV4Host &ia, tpport_t port)
172{
173 int len = sizeof(peer.ipv4);
174
175 peer.ipv4.sin_family = AF_INET;
176 peer.ipv4.sin_addr = getaddress(ia);
177 peer.ipv4.sin_port = htons(port);
178 // Win32 will crash if you try to connect to INADDR_ANY.
179 if ( INADDR_ANY == peer.ipv4.sin_addr.s_addr )
180 peer.ipv4.sin_addr.s_addr = INADDR_LOOPBACK;
181 if(::connect(so, (struct sockaddr *)&peer.ipv4, len))
182 return connectError();
183 return errSuccess;
184}
185
186#ifdef CCXX_IPV6
187Socket::Error UDPReceive::connect(const IPV6Host &ia, tpport_t port)
188{
189 int len = sizeof(peer.ipv6);
190
191 peer.ipv6.sin6_family = AF_INET6;
192 peer.ipv6.sin6_addr = getaddress(ia);
193 peer.ipv6.sin6_port = htons(port);
194 // Win32 will crash if you try to connect to INADDR_ANY.
195 if(!memcmp(&peer.ipv6.sin6_addr, &in6addr_any, sizeof(in6addr_any)))
196 memcpy(&peer.ipv6.sin6_addr, &in6addr_loopback, sizeof(in6addr_loopback));
197 if(::connect(so, (sockaddr *)&peer.ipv6, len))
198 return connectError();
199 return errSuccess;
200}
201#endif
202
203UDPDuplex::UDPDuplex(const IPV4Address &bind, tpport_t port) :
204UDPTransmit(bind, port + 1), UDPReceive(bind, port)
205{}
206
207#ifdef CCXX_IPV6
208UDPDuplex::UDPDuplex(const IPV6Address &bind, tpport_t port) :
209UDPTransmit(bind, port + 1), UDPReceive(bind, port)
210{}
211#endif
212
213Socket::Error UDPDuplex::connect(const IPV4Host &host, tpport_t port)
214{
215 Error rtn = UDPTransmit::connect(host, port);
216 if(rtn) {
217 UDPTransmit::disconnect();
218 UDPReceive::disconnect();
219 return rtn;
220 }
221 return UDPReceive::connect(host, port + 1);
222}
223
224#ifdef CCXX_IPV6
225Socket::Error UDPDuplex::connect(const IPV6Host &host, tpport_t port)
226{
227 Error rtn = UDPTransmit::connect(host, port);
228 if(rtn) {
229 UDPTransmit::disconnect();
230 UDPReceive::disconnect();
231 return rtn;
232 }
233 return UDPReceive::connect(host, port + 1);
234}
235#endif
236
237Socket::Error UDPDuplex::disconnect(void)
238{
239 Error rtn = UDPTransmit::disconnect();
240 Error rtn2 = UDPReceive::disconnect();
241 if (rtn) return rtn;
242 return rtn2;
243}
244
245#ifdef CCXX_NAMESPACES
246}
247#endif