blob: f8606c0db478441e9e8d83c0892a80aaf1de7624 [file] [log] [blame]
Emeric Vigier2f625822012-08-06 11:09:52 -04001// Copyright (C) 2002-2010 Wizzer Works.
2//
3// This program is free software; you can redistribute it and/or modify
4// it under the terms of the GNU General Public License as published by
5// the Free Software Foundation; either version 2 of the License, or
6// (at your option) any later version.
7//
8// This program is distributed in the hope that it will be useful,
9// but WITHOUT ANY WARRANTY; without even the implied warranty of
10// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11// GNU General Public License for more details.
12//
13// You should have received a copy of the GNU General Public License
14// along with this program; if not, write to the Free Software
15// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
16//
17// As a special exception, you may use this file as part of a free software
18// library without restriction. Specifically, if other files instantiate
19// templates or use macros or inline functions from this file, or you compile
20// this file and link it with other files to produce an executable, this
21// file does not by itself cause the resulting executable to be covered by
22// the GNU General Public License. This exception does not however
23// invalidate any other reasons why the executable file might be covered by
24// the GNU General Public License.
25//
26// This exception applies only to the code released under the name GNU
27// Common C++. If you copy code from other releases into a copy of GNU
28// Common C++, as the General Public License permits, the exception does
29// not apply to the code that you add in this way. To avoid misleading
30// anyone as to the status of such modified files, you must delete
31// this exception notice from them.
32//
33// If you write modifications of your own for GNU Common C++, it is your choice
34// whether to permit this exception to apply to your modifications.
35// If you do not wish that, delete this exception notice.
36//
37
38/**
39 * @file simplesocket.cpp
40 * @brief Implementation of SimpleTCPStream methods.
41 *
42 * Implementation of SimpleTCPStream methods.
43 *
44 * @author Mark S. Millard (msm@wizzer.com)
45 * @date 2002-08-15
46 */
47
48// Include Common C++ Library header files.
49#include <cc++/config.h>
50#include <cc++/export.h>
51#include <cc++/socket.h>
52
53#ifndef INADDR_LOOPBACK
54#define INADDR_LOOPBACK (unsigned long)0x7f000001
55#endif
56
57#ifdef CCXX_NAMESPACES
58namespace ost {
59using namespace std;
60#endif
61
62SimpleTCPStream::SimpleTCPStream(TCPSocket &server, size_t size) :
63Socket(accept(server.getSocket(), NULL, NULL))
64{
65 tpport_t port;
66 IPV4Host host = getPeer(&port);
67
68 if (! server.onAccept(host, port)) {
69 endSocket();
70 error(errConnectRejected);
71 return;
72 }
73
74 Socket::state = CONNECTED;
75}
76
77SimpleTCPStream::SimpleTCPStream(const IPV4Host &host, tpport_t port, size_t size) :
78Socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)
79{
80 Connect(host, port, size);
81}
82
83SimpleTCPStream::~SimpleTCPStream()
84{
85 endStream();
86}
87
88IPV4Host SimpleTCPStream::getSender(tpport_t *port) const
89{
90 return IPV4Host();
91}
92
93void SimpleTCPStream::Connect(const IPV4Host &host, tpport_t port, size_t size)
94{
95 size_t i;
96
97 for (i = 0 ; i < host.getAddressCount(); i++) {
98 struct sockaddr_in addr;
99 memset(&addr, 0, sizeof(addr));
100 addr.sin_family = AF_INET;
101 addr.sin_addr = host.getAddress(i);
102 addr.sin_port = htons(port);
103
104 // Win32 will crash if you try to connect to INADDR_ANY.
105 if ( INADDR_ANY == addr.sin_addr.s_addr )
106 addr.sin_addr.s_addr = INADDR_LOOPBACK;
107 if (::connect(so, (struct sockaddr *)&addr, (socklen_t)sizeof(addr)) == 0)
108 break;
109 }
110
111 if (i == host.getAddressCount()) {
112 connectError();
113 endSocket();
114 return;
115 }
116
117 Socket::state = CONNECTED;
118}
119
120SimpleTCPStream::SimpleTCPStream() :
121Socket(PF_INET, SOCK_STREAM, IPPROTO_TCP) {}
122
123SimpleTCPStream::SimpleTCPStream(const SimpleTCPStream &source) :
124#ifdef WIN32
125Socket(source.so)
126#else
127Socket(dup(source.so))
128#endif
129{}
130
131void SimpleTCPStream::endStream(void)
132{
133 endSocket();
134}
135
136ssize_t SimpleTCPStream::read(char *bytes, size_t length, timeout_t timeout)
137{
138 // Declare local variables.
139 ssize_t rlen = 0;
140 size_t totalrecv = 0;
141 char *currentpos = bytes;
142
143 // Check for reasonable requested length.
144 if (length < 1) {
145 return (ssize_t)totalrecv;
146 }
147
148 while (totalrecv < length) {
149 // Check for timeout condition.
150 if (timeout) {
151 if (! isPending(pendingInput, timeout)) {
152 error(errTimeout);
153 return -1;
154 }
155 }
156
157 // Attempt to read data.
158 rlen = _IORET64 ::recv(so, (char *) currentpos, _IOLEN64 (length-totalrecv), 0);
159 if (rlen == 0 || rlen == -1) {
160 break;
161 }
162 // cout << "received " << rlen << " bytes, remaining " << length - totalrecv << flush;
163
164 totalrecv += rlen;
165 currentpos += rlen;
166 }
167
168 // Set error condition if necessary.
169 if (rlen == -1) {
170 error(errInput);
171 }
172
173 // Return total number of bytes recieved.
174 return (ssize_t)totalrecv;
175}
176
177ssize_t SimpleTCPStream::write(const char *bytes, size_t length, timeout_t timeout)
178{
179 // Declare local variables.
180 ssize_t rlen = 0;
181
182 // Check for reasonable requested length.
183 if (length < 1) {
184 return rlen;
185 }
186
187 // Check for timeout condition.
188 if (timeout) {
189 if (! isPending(pendingOutput, timeout)) {
190 error(errTimeout);
191 return -1;
192 }
193 }
194
195 // Attempt to write data.
196 rlen = _IORET64 ::send(so, (const char *)bytes, _IOLEN64 length, MSG_NOSIGNAL);
197 if (rlen == -1) {
198 error(errOutput);
199 }
200
201 return rlen;
202}
203
204ssize_t SimpleTCPStream::peek(char *bytes, size_t length, timeout_t timeout)
205{
206 // Declare local variables.
207 ssize_t rlen = 0;
208 size_t totalrecv = 0;
209 char *currentpos = bytes;
210
211 // Check for reasonable requested length.
212 if (length < 1) {
213 return (ssize_t)totalrecv;
214 }
215
216 while (totalrecv < length) {
217 // Check for timeout condition.
218 if (timeout) {
219 if (! isPending(pendingInput, timeout)) {
220 error(errTimeout);
221 return -1;
222 }
223 }
224
225 // Attempt to read data.
226 rlen = _IORET64 ::recv(so, (char *) currentpos, _IOLEN64 (length-totalrecv), MSG_PEEK);
227 if (rlen == 0 || rlen == -1) {
228 break;
229 }
230 // cout << "received " << rlen << " bytes, remaining " << length - totalrecv << flush;
231
232 totalrecv += rlen;
233 currentpos += rlen;
234 }
235
236 // Set error condition if necessary.
237 if (rlen == -1) {
238 error(errInput);
239 }
240
241 // Return total number of bytes recieved.
242 return (ssize_t)totalrecv;
243}
244
245bool SimpleTCPStream::isPending(Pending pending, timeout_t timeout)
246{
247 return Socket::isPending(pending, timeout);
248}
249
250#ifdef CCXX_NAMESPACES
251} /* for ost */
252#endif
253
254/** EMACS **
255 * Local variables:
256 * mode: c++
257 * c-basic-offset: 4
258 * End:
259 */