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 /*----------------------------------------------------------------------------*/
33 template<typename CharT, typename Traits>
34 const 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  */
43 template<typename CharT, typename Traits>
44 claw::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  */
55 template<typename CharT, typename Traits>
56 claw::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  */
69 template<typename CharT, typename Traits>
70 typename claw::net::basic_socketbuf<CharT, Traits>::self_type*
71 claw::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  */
97 template<typename CharT, typename Traits>
98 typename claw::net::basic_socketbuf<CharT, Traits>::self_type*
99 claw::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  */
128 template<typename CharT, typename Traits>
129 typename claw::net::basic_socketbuf<CharT, Traits>::self_type*
130 claw::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  */
142 template<typename CharT, typename Traits>
143 bool 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  */
154 template<typename CharT, typename Traits>
155 void 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  */
166 template<typename CharT, typename Traits>
167 int 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  */
195 template<typename CharT, typename Traits>
196 typename claw::net::basic_socketbuf<CharT, Traits>::int_type
197 claw::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  */
232 template<typename CharT, typename Traits>
233 typename claw::net::basic_socketbuf<CharT, Traits>::int_type
234 claw::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  */
260 template<typename CharT, typename Traits>
261 bool 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  */
274 template<typename CharT, typename Traits>
275 void 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  */
295 template<typename CharT, typename Traits>
296 void 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  */
319 template<typename CharT, typename Traits>
320 bool 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()