Claw 1.7.3
basic_socketbuf.tpp
1/*
2 CLAW - a C++ Library Absolutely Wonderful
3
4 CLAW is a free library without any particular aim but being useful to
5 anyone.
6
7 Copyright (C) 2005-2011 Julien Jorge
8
9 This library is free software; you can redistribute it and/or
10 modify it under the terms of the GNU Lesser General Public
11 License as published by the Free Software Foundation; either
12 version 2.1 of the License, or (at your option) any later version.
13
14 This library is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 Lesser General Public License for more details.
18
19 You should have received a copy of the GNU Lesser General Public
20 License along with this library; if not, write to the Free Software
21 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
22
23 contact: julien.jorge@gamned.org
24*/
25/**
26 * \file basic_socketbuf.tpp
27 * \brief Implantation of the claw::net::basic_socketbuf class.
28 * \author Julien Jorge
29 */
30#include <claw/assert.hpp>
31
32/*----------------------------------------------------------------------------*/
33template<typename CharT, typename Traits>
34const size_t claw::net::basic_socketbuf<CharT, Traits>::s_buffer_size = 256;
35
36/*----------------------------------------------------------------------------*/
37/**
38 * \brief Constructor.
39 * \param read_limit Number of second to wait before considering nothing will
40 * come in the socket. Negative values mean infinity.
41 * \post is_open() == false;
42 */
43template<typename CharT, typename Traits>
44claw::net::basic_socketbuf<CharT, Traits>::basic_socketbuf( int read_limit )
45 : m_read_limit(read_limit), m_input_buffer(NULL), m_input_buffer_size(0),
46 m_output_buffer(NULL), m_output_buffer_size(0)
47{
48 create_buffers();
49} // basic_socketbuf::basic_socketbuf()
50
51/*----------------------------------------------------------------------------*/
52/**
53 * \brief Destructor.
54 */
55template<typename CharT, typename Traits>
56claw::net::basic_socketbuf<CharT, Traits>::~basic_socketbuf()
57{
58 close();
59 destroy_buffers();
60} // basic_socketbuf::basic_socketbuf()
61
62/*----------------------------------------------------------------------------*/
63/**
64 * \brief Initialise the socket.
65 * \param address Address to open.
66 * \param port The port to connect to.
67 * \return this if everything works fine, NULL otherwise.
68 */
69template<typename CharT, typename Traits>
70typename claw::net::basic_socketbuf<CharT, Traits>::self_type*
71claw::net::basic_socketbuf<CharT, Traits>::open
72( const std::string& address, int port )
73{
74 self_type* result = NULL;
75
76 if (!this->is_open())
77 if ( basic_socket::open() )
78 {
79 if ( connect( address, port ) )
80 result = this;
81 else
82 close();
83 }
84
85 return result;
86} // basic_socketbuf::open()
87
88/*----------------------------------------------------------------------------*/
89/**
90 * \brief Link the socket to a file descriptor.
91 * \param d The file descriptor.
92 * \return this if everything works fine, NULL otherwise.
93 * \remark This method should be only called by claw::net::basic_*socket_stream.
94 * \remark If this socket was open and \a fd is valid, the socket will be closed
95 * before that \a d will be assigned.
96 */
97template<typename CharT, typename Traits>
98typename claw::net::basic_socketbuf<CharT, Traits>::self_type*
99claw::net::basic_socketbuf<CharT, Traits>::open( socket_traits::descriptor d )
100{
101 self_type* result = NULL;
102
103 if ( socket_traits::is_open(d) )
104 {
105 if (this->is_open())
106 {
107 if ( close() )
108 {
109 result = this;
110 m_descriptor = d;
111 }
112 }
113 else
114 {
115 result = this;
116 m_descriptor = d;
117 }
118 }
119
120 return result;
121} // basic_socketbuf::open()
122
123/*----------------------------------------------------------------------------*/
124/**
125 * \brief Close the socket.
126 * \post is_open() == false;
127 */
128template<typename CharT, typename Traits>
129typename claw::net::basic_socketbuf<CharT, Traits>::self_type*
130claw::net::basic_socketbuf<CharT, Traits>::close()
131{
132 if ( basic_socket::close() )
133 return this;
134 else
135 return NULL;
136} // basic_socketbuf::close()
137
138/*----------------------------------------------------------------------------*/
139/**
140 * \brief Tell if the socket is open.
141 */
142template<typename CharT, typename Traits>
143bool claw::net::basic_socketbuf<CharT, Traits>::is_open() const
144{
145 return basic_socket::is_open();
146} // // basic_socketbuf::is_open()
147
148/*----------------------------------------------------------------------------*/
149/**
150 * \brief Set the number of second to wait before considering nothing will come
151 * in the socket.
152 * \param read_limit The number of seconds. Negative values mean infinity.
153 */
154template<typename CharT, typename Traits>
155void claw::net::basic_socketbuf<CharT, Traits>::set_read_time_limit
156( int read_limit )
157{
158 m_read_limit = read_limit;
159} // // basic_socketbuf::set_read_time_limit()
160
161/*----------------------------------------------------------------------------*/
162/**
163 * \brief Write the buffered data in the socket.
164 * \pre is_open()
165 */
166template<typename CharT, typename Traits>
167int claw::net::basic_socketbuf<CharT, Traits>::sync()
168{
169 CLAW_PRECOND( is_open() );
170 CLAW_PRECOND( buffered() );
171
172 ssize_t write_count = 0;
173 ssize_t length = (this->pptr() - this->pbase()) * sizeof(char_type);
174 int_type result = 0;
175
176 if ( length > 0 )
177 write_count = send(m_descriptor, static_cast<const char*>(this->pbase()),
178 length, 0 );
179
180 if ( write_count >= 0 )
181 this->setp( m_output_buffer, m_output_buffer + m_output_buffer_size );
182 else
183 result = -1;
184
185 return result;
186} // basic_socketbuf::sync()
187
188/*----------------------------------------------------------------------------*/
189/**
190 * \brief Fill the input buffer.
191 * \pre is_open() && gptr() != NULL
192 * \return The next symbol to be read ( *gptr() ) if there is data coming from
193 * the socket, traits::eof() otherwise.
194 */
195template<typename CharT, typename Traits>
196typename claw::net::basic_socketbuf<CharT, Traits>::int_type
197claw::net::basic_socketbuf<CharT, Traits>::underflow()
198{
199 CLAW_PRECOND( buffered() );
200 CLAW_PRECOND( this->gptr() >= this->egptr() );
201
202 ssize_t read_count;
203 ssize_t length = m_input_buffer_size * sizeof(char_type);
204 int_type result = traits_type::eof();
205
206 if( !is_open() )
207 return result;
208
209 if ( socket_traits::select_read(m_descriptor, m_read_limit) )
210 read_count = recv(m_descriptor, static_cast<char*>(m_input_buffer), length,
211 0);
212 else
213 read_count = -1;
214
215 if ( read_count > 0 )
216 {
217 this->setg( m_input_buffer, m_input_buffer, m_input_buffer + read_count);
218 result = this->sgetc();
219 }
220 else
221 this->setg( m_input_buffer, m_input_buffer + m_input_buffer_size,
222 m_input_buffer + m_input_buffer_size );
223
224 return result;
225} // basic_socketbuf::underflow()
226
227/*----------------------------------------------------------------------------*/
228/**
229 * \brief Synchronize the output buffer (ie. write in the socket).
230 * \param c
231 */
232template<typename CharT, typename Traits>
233typename claw::net::basic_socketbuf<CharT, Traits>::int_type
234claw::net::basic_socketbuf<CharT, Traits>::overflow( int_type c )
235{
236 CLAW_PRECOND( is_open() );
237 CLAW_PRECOND( buffered() );
238
239 int_type result = traits_type::eof();
240
241 if ( sync() == 0 )
242 {
243 result = traits_type::not_eof(c);
244
245 if ( !traits_type::eq_int_type(c, traits_type::eof()) )
246 this->sputc(c);
247 }
248
249 return result;
250} // basic_socketbuf::overflow()
251
252/*----------------------------------------------------------------------------*/
253/**
254 * \brief Connect the socket to a port.
255 * \param addr The address to connect to.
256 * \param port The port to connect to.
257 * \return true if the connection is established.
258 * \pre m_fd is a valid socket descriptor.
259 */
260template<typename CharT, typename Traits>
261bool claw::net::basic_socketbuf<CharT, Traits>::connect
262( const std::string& addr, int port )
263{
264 CLAW_PRECOND( socket_traits::valid_descriptor(m_descriptor) );
265
266 return socket_traits::connect(m_descriptor, addr, port);
267} // basic_socketbuf::connect()
268
269/*----------------------------------------------------------------------------*/
270/**
271 * \brief Create the buffers.
272 * \pre pbase() == eback() == NULL
273 */
274template<typename CharT, typename Traits>
275void claw::net::basic_socketbuf<CharT, Traits>::create_buffers()
276{
277 CLAW_PRECOND( this->pbase() == NULL );
278 CLAW_PRECOND( this->eback() == NULL );
279
280 m_input_buffer_size = m_output_buffer_size = s_buffer_size;
281
282 m_input_buffer = new char_type[m_input_buffer_size];
283 m_output_buffer = new char_type[m_output_buffer_size];
284
285 this->setg( m_input_buffer, m_input_buffer + m_input_buffer_size,
286 m_input_buffer + m_input_buffer_size );
287 this->setp( m_output_buffer, m_output_buffer + m_output_buffer_size );
288} // basic_socketbuf::create_buffers()
289
290/*----------------------------------------------------------------------------*/
291/**
292 * \brief Destroy the buffers.
293 * \post pbase() == eback() == NULL
294 */
295template<typename CharT, typename Traits>
296void claw::net::basic_socketbuf<CharT, Traits>::destroy_buffers()
297{
298 if ( m_input_buffer )
299 {
300 delete[] m_input_buffer;
301 m_input_buffer = NULL;
302 }
303
304 if ( m_output_buffer )
305 {
306 delete[] m_output_buffer;
307 m_output_buffer = NULL;
308 }
309
310 this->setg( NULL, NULL, NULL );
311 this->setp( NULL, NULL );
312} // basic_socketbuf::destroy_buffers()
313
314/*----------------------------------------------------------------------------*/
315/**
316 * \brief Tell if we use buffered input and output.
317 * \remark Should always be true !
318 */
319template<typename CharT, typename Traits>
320bool claw::net::basic_socketbuf<CharT, Traits>::buffered() const
321{
322 return this->pbase() && this->pptr() && this->epptr()
323 && this->eback() && this->gptr() && this->egptr();
324} // basic_socketbuf::buffered()