libsocket  1.5
netsocket.cc
Go to the documentation of this file.
1 /*
2 ** netsocket.cc
3 ** Login : Julien Lemoine <speedblue@happycoder.org>
4 ** Started on Mon May 12 22:23:27 2003 Julien Lemoine
5 ** $Id: netsocket.cc,v 1.13 2004/11/24 21:25:36 speedblue Exp $
6 **
7 ** Copyright (C) 2003,2004 Julien Lemoine
8 ** This program is free software; you can redistribute it and/or modify
9 ** it under the terms of the GNU Lesser General Public License as published by
10 ** the Free Software Foundation; either version 2 of the License, or
11 ** (at your option) any later version.
12 **
13 ** This program is distributed in the hope that it will be useful,
14 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
15 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 ** GNU Lesser General Public License for more details.
17 **
18 ** You should have received a copy of the GNU Lesser General Public License
19 ** along with this program; if not, write to the Free Software
20 ** Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21 */
22 
23 #include <iostream>
24 #include "netsocket.hh"
25 #include "socket.hxx"
26 
27 namespace Network
28 {
29 
30  struct sockaddr_in NetSocket::_get_addr(const std::string& host,
31  int port) const
32  {
33  struct hostent *he;
34  struct sockaddr_in addr;
35 
36  memset(&addr, 0, sizeof(struct sockaddr_in));
37  he = gethostbyname(host.c_str());
38  if (!he)
39  throw HostnameError("Unknown Hostname", HERE);
40  addr.sin_addr = *((struct in_addr *)he->h_addr);
41  addr.sin_port = htons(port);
42  addr.sin_family = AF_INET;
43  return addr;
44  }
45 
46 #ifdef IPV6_ENABLED
47  struct sockaddr_in6 NetSocket::_get_addr6(const std::string& host,
48  int port) const
49  {
50  struct sockaddr_in6 addr;
51 
52  memset(&addr, 0, sizeof(struct sockaddr_in6));
53  if ( inet_pton(AF_INET6, host.c_str(), &addr.sin6_addr) == 0 )
54  throw InetptonError("Unknown Hostname", HERE);
55  addr.sin6_port = htons(port);
56  addr.sin6_family = AF_INET6;
57  return addr;
58  }
59 #endif
60 
61  struct sockaddr_in NetSocket::_get_addr(int port) const
62  {
63  struct sockaddr_in addr;
64 
65  memset(&addr, 0, sizeof(struct sockaddr_in));
66  addr.sin_addr.s_addr = htonl(INADDR_ANY);
67  addr.sin_port = htons(port);
68  addr.sin_family = AF_INET;
69  return addr;
70  }
71 
72 #ifdef IPV6_ENABLED
73  struct sockaddr_in6 NetSocket::_get_addr6(int port) const
74  {
75  struct sockaddr_in6 addr;
76 
77  memset(&addr, 0, sizeof(struct sockaddr_in6));
78  if ( inet_pton(AF_INET6, "0::0", &addr.sin6_addr) == 0 )
79  throw InetptonError("Not a valid address", HERE);
80  addr.sin6_port = htons(port);
81  addr.sin6_family = AF_INET6;
82  return addr;
83  }
84 #endif
85 
86  int NetSocket::_bind(int port, const std::string& host)
87  {
88  int s;
89 
90  if (_kind == UDP)
91  {
92 #ifdef IPV6_ENABLED
93  if (_version == V4)
94 #endif
95  s = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP);
96 #ifdef IPV6_ENABLED
97  else
98  s = socket(PF_INET6, SOCK_DGRAM, IPPROTO_UDP);
99 #endif
100  }
101  else if (_kind == TCP)
102  {
103 #ifdef IPV6_ENABLED
104  if (_version == V4)
105 #endif
106  s = socket(PF_INET, SOCK_STREAM, 0);
107 #ifdef IPV6_ENABLED
108  else
109  s = socket(PF_INET6, SOCK_STREAM, 0);
110 #endif
111  }
112  else
113  throw Exception("Unknown Protocole", HERE);
114 
115  if (s < 0)
116  throw SocketError("Socket error", HERE);
117 #ifdef IPV6_ENABLED
118  if (_version == V4)
119 #endif
120  _addr = _get_addr(host, port);
121 #ifdef IPV6_ENABLED
122  else
123  _addr6 = _get_addr6(host, port);
124 #endif
125  return s;
126  }
127 
128  int NetSocket::_bind(int port)
129  {
130  int s, on;
131 
132  if (_kind == TCP)
133  {
134 #ifdef IPV6_ENABLED
135  if (_version == V4)
136 #endif
137  s = socket(PF_INET, SOCK_STREAM, 0);
138 #ifdef IPV6_ENABLED
139  else
140  s = socket(PF_INET6, SOCK_STREAM, 0);
141 #endif
142  }
143  else if (_kind == UDP)
144  {
145 #ifdef IPV6_ENABLED
146  if (_version == V4)
147 #endif
148  s = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP);
149 #ifdef IPV6_ENABLED
150  else
151  s = socket(PF_INET6, SOCK_DGRAM, IPPROTO_UDP);
152 #endif
153  }
154  else
155  throw Exception("Unknown Protocole", HERE);
156  if (s < 0)
157  throw SocketError("Socket error", HERE);
158  on = 1;
159 
160  if (_kind == TCP && setsockopt(s, SOL_SOCKET,
161  SO_REUSEADDR, (void *)&on,
162  sizeof (on)) == -1)
163  throw SetsockoptError("setsockopt error", HERE);
164 
165 #ifdef IPV6_ENABLED
166  if (_version == V4)
167  {
168 #endif
169  struct sockaddr_in addr;
170  addr = _get_addr(port);
171  if (bind(s,(struct sockaddr*)&addr, (int)sizeof(addr)) == -1)
172  throw BindError("Bind error", HERE);
173 #ifdef IPV6_ENABLED
174  }
175  else
176  {
177  struct sockaddr_in6 addr6;
178  addr6 = _get_addr6(port);
179  if (bind(s,(struct sockaddr*)&addr6, (int)sizeof(addr6)) == -1)
180  throw BindError("Bind error", HERE);
181  }
182 #endif
183  return s;
184  }
185 
186  void NetSocket::_connect(int socket, int port,
187  const std::string& host) const
188  {
189 #ifdef IPV6_ENABLED
190  if (_version == V4)
191  {
192 #endif
193  struct sockaddr_in addr;
194  addr = _get_addr(host, port);
195  if (connect(socket, (struct sockaddr *)&addr,
196  sizeof (addr)) < 0)
197  throw ConnectError("Unable to connect", HERE);
198 #ifdef IPV6_ENABLED
199  }
200  else
201  {
202  struct sockaddr_in6 addr6;
203  addr6 = _get_addr6(host, port);
204  if (connect(socket, (struct sockaddr *)&addr6,
205  sizeof (addr6)) < 0)
206  throw ConnectError("Unable to connect", HERE);
207  }
208 #endif
209  }
210 
211  int NetSocket::_accept(int port, int socket) const
212  {
213 #ifdef LIBSOCKET_WIN
214  int size;
215 #else
216  socklen_t size;
217 #endif
218  int s;
219  struct sockaddr_in addr;
220 #ifdef IPV6_ENABLED
221  struct sockaddr_in6 addr6;
222 
223  if (_version == V4)
224  {
225 #endif
226  addr = _get_addr(port);
227  size = sizeof(addr);
228  s = accept(socket, (struct sockaddr*)&addr, &size);
229 #ifdef IPV6_ENABLED
230  }
231  else
232  {
233  addr6 = _get_addr6(port);
234  size = sizeof(addr6);
235  s = accept(socket, (struct sockaddr*)&addr6, &size);
236  }
237 #endif
238  if (s < 0)
239  throw AcceptError("Accept Error", HERE);
240  return s;
241  }
242 
243  std::string NetSocket::_get_ip(int port, int socket) const
244  {
245  struct sockaddr_in addr;
246 #ifdef LIBSOCKET_WIN
247  int size;
248 #else
249  socklen_t size;
250 #endif
251 
252  memset(&addr, '\0', sizeof(addr));
253  addr.sin_family = AF_INET;
254  addr.sin_addr.s_addr = htonl(INADDR_ANY);
255  addr.sin_port = htons(port);
256  size = sizeof(addr);
257  getpeername(socket, (struct sockaddr *)&addr, &size);
258  return(std::string(inet_ntoa(addr.sin_addr)));
259  }
260 
261  std::string NetSocket::_read_line(int socket)
262  {
263  char chr[MAXPKTSIZE];
264  std::string str = "";
265  int res = 1, i;
266  std::pair<int, int> delim;
267  bool end = false;
268 
269  if (socket < 0)
270  throw NoConnection("No Socket", HERE);
271  if (!_update_buffer(delim, i, str))
272  while (!end)
273  {
274  memset(chr, 0, MAXPKTSIZE);
275  if (_state_timeout)
276  _set_timeout(true, _socket, _state_timeout);
277  if (_kind == UDP)
278 #ifdef LIBSOCKET_WIN
279  res = recv(socket, chr, MAXPKTSIZE, 0);
280 #else
281  res = recv(socket, chr, MAXPKTSIZE, MSG_TRUNC);
282 #endif
283  else
284 #ifdef TLS
285  if (_tls)
286  res = gnutls_record_recv(_session, chr, MAXPKTSIZE);
287  else
288 #endif
289  res = recv(socket, chr, MAXPKTSIZE, 0);
290  if (_check_answer(res, str))
291  return str;
292  _buffer += std::string(chr, res);
293  if (_update_buffer(delim, i, str))
294  end = true;
295  }
296  _state_timeout = 0;
297  return str;
298  }
299 
300  std::string NetSocket::_read_line(int socket, int& port,
301  std::string& host)
302  {
303  char chr[MAXPKTSIZE];
304  std::string str = "";
305  int res = 1, i;
306  std::pair<int, int> delim;
307  struct sockaddr_in addr;
308 #ifdef IPV6_ENABLED
309  struct sockaddr_in6 addr6;
310 #endif
311 #ifdef LIBSOCKET_WIN
312  int size;
313 #else
314  socklen_t size;
315 #endif
316  bool end = false;
317 
318 #ifdef IPV6_ENABLED
319  if (V4 == _version)
320 #endif
321  size = sizeof(addr);
322 #ifdef IPV6_ENABLED
323  else
324  size = sizeof(addr6);
325 #endif
326  if (socket < 0)
327  throw NoConnection("No Socket", HERE);
328  if (!_update_buffer(delim, i, str))
329  while (!end)
330  {
331  if (_state_timeout)
332  _set_timeout(true, _socket, _state_timeout);
333  if (_kind == UDP)
334  {
335 #ifdef LIBSOCKET_WIN
336  int flags = 0;
337 #else
338  int flags = MSG_TRUNC;
339 #endif
340 
341 #ifdef IPV6_ENABLED
342  if (V4 == _version)
343 #endif
344  res = recvfrom(socket, chr, MAXPKTSIZE, flags,
345  (struct sockaddr *) &addr, &size);
346 #ifdef IPV6_ENABLED
347  else
348  res = recvfrom(socket, chr, MAXPKTSIZE, flags,
349  (struct sockaddr *) &addr6, &size);
350 #endif
351  }
352  else
353  {
354 #ifdef TLS
355  if (_tls)
356  res = gnutls_record_recv(_session, chr, MAXPKTSIZE);
357  else
358 #endif
359  res = recvfrom(socket, chr, MAXPKTSIZE, 0, NULL, 0);
360 #ifdef IPV6_ENABLED
361  if (V4 == _version)
362  {
363 #endif
364  if (getpeername(socket, (struct sockaddr *) &addr, &size) < 0)
365  throw GetpeernameError("getpeername error", HERE);
366 #ifdef IPV6_ENABLED
367  }
368  else
369  if (getpeername(socket, (struct sockaddr *) &addr6, &size) < 0)
370  throw GetpeernameError("getpeername error", HERE);
371 #endif
372  }
373  if (_check_answer(res, str))
374  return str;
375  _buffer += std::string(chr, res);
376  if (_update_buffer(delim, i, str))
377  end = true;
378  }
379 #ifdef IPV6_ENABLED
380  if (V4 == _version)
381  {
382 #endif
383  host = std::string(inet_ntoa(addr.sin_addr));
384  port = ntohs(addr.sin_port);
385 #ifdef IPV6_ENABLED
386  }
387  else
388  {
389  char buf[INET6_ADDRSTRLEN];
390  if (inet_ntop(AF_INET6, &addr6.sin6_addr, buf, INET6_ADDRSTRLEN) == 0)
391  throw InetntopError("Not a valid address", HERE);
392  host = std::string(buf);
393  port = ntohs(addr6.sin6_port);
394  }
395 #endif
396  _state_timeout = 0;
397  return str;
398  }
399 
400  void NetSocket::_write_str(int socket, const std::string& str,
401  const std::string& host, int port) const
402  {
403  struct sockaddr_in addr;
404 #ifdef IPV6_ENABLED
405  struct sockaddr_in6 addr6;
406 #endif
407  int res = 1;
408  const char *buf = str.c_str();
409  unsigned int count = 0;
410 
411 #ifdef IPV6_ENABLED
412  if (V4 == _version)
413 #endif
414  addr = _get_addr(host, port);
415 #ifdef IPV6_ENABLED
416  else
417  addr6 = _get_addr6(host, port);
418 #endif
419  if (socket < 0)
420  throw NoConnection("No Socket", HERE);
421  while (res && count < str.size())
422  {
423 #ifdef IPV6_ENABLED
424  if (V4 == _version)
425 #endif
426 #ifdef TLS
427  if (_tls)
428  res = gnutls_record_send(_session, buf + count, str.size() - count);
429  else
430 #endif
431  res = sendto(socket, buf + count,
432  str.size() - count, SENDTO_FLAGS,
433  (const struct sockaddr*)&addr, sizeof(_addr));
434 #ifdef IPV6_ENABLED
435  else
436  res = sendto(socket, buf + count,
437  str.size() - count, SENDTO_FLAGS,
438  (const struct sockaddr*)&addr6, sizeof(_addr6));
439 #endif
440  if (res <= 0)
441  throw ConnectionClosed("Connection Closed", HERE);
442  count += res;
443  }
444  }
445 
446  void NetSocket::_write_str_bin(int socket, const std::string& str,
447  const std::string& host, int port) const
448  {
449  struct sockaddr_in addr;
450 #ifdef IPV6_ENABLED
451  struct sockaddr_in6 addr6;
452 #endif
453  int res = 1;
454  unsigned int count = 0;
455 #ifdef LIBSOCKET_WIN
456  char* buf = new char[str.size() + 2];
457 #else
458  char buf[str.size() + 2];
459 #endif
460 
461  buf[0] = str.size() / 256;
462  buf[1] = str.size() % 256;
463  memcpy(buf + 2, str.c_str(), str.size());
464 #ifdef IPV6_ENABLED
465  if (V4 == _version)
466 #endif
467  addr = _get_addr(host, port);
468 #ifdef IPV6_ENABLED
469  else
470  addr6 = _get_addr6(host, port);
471 #endif
472  if (socket < 0)
473  throw NoConnection("No Socket", HERE);
474  while (res && count < str.size() + 2)
475  {
476 #ifdef IPV6_ENABLED
477  if (V4 == _version)
478 #endif
479 #ifdef TLS
480  if (_tls)
481  res = gnutls_record_send(_session, buf + count, str.size() + 2 - count);
482  else
483 #endif
484  res = sendto(socket, buf + count, str.size() + 2 - count,
485  SENDTO_FLAGS,
486  (const struct sockaddr*)&addr, sizeof(_addr));
487 #ifdef IPV6_ENABLED
488  else
489  res = sendto(socket, buf + count, str.size() + 2 - count,
490  SENDTO_FLAGS,
491  (const struct sockaddr*)&addr6, sizeof(_addr6));
492 #endif
493  if (res <= 0)
494  throw ConnectionClosed("Connection Closed", HERE);
495  count += res;
496  }
497 #ifdef LIBSOCKET_WIN
498  delete[] buf;
499 #endif
500  }
501 
502  void NetSocket::writeto(const std::string& str,
503  const std::string& host, int port)
504  {
505  if (_proto_kind == binary)
506  _write_str_bin(_socket, str, host, port);
507  else
508  _write_str(_socket, str, host, port);
509  }
510 
511  std::string NetSocket::read(int& port, std::string& host)
512  {
513  if (_proto_kind == binary)
514  return _read_line_bin(_socket, port, host, 0);
515  else
516  return _read_line(_socket, port, host);
517  }
518 
519  std::string NetSocket::read(int& port, std::string& host, int timeout)
520  {
521  if (_proto_kind == binary)
522  {
523  _set_timeout(true, _socket, timeout);
524  return _read_line_bin(_socket, port, host, 0);
525  }
526  else
527  {
528  _state_timeout = timeout;
529  return _read_line(_socket, port, host);
530  }
531  }
532 
533  std::string NetSocket::read()
534  {
535  if (_proto_kind == binary)
536  return _read_line_bin(_socket, 0);
537  else
538  return _read_line(_socket);
539  }
540 
541  std::string NetSocket::read(int timeout)
542  {
543  if (_proto_kind == binary)
544  {
545  _set_timeout(true, _socket, timeout);
546  return _read_line_bin(_socket, 0);
547  }
548  else
549  {
550  _state_timeout = timeout;
551  return _read_line(_socket);
552  }
553  }
554 
555  std::string NetSocket::readn(int& port, std::string& host,
556  unsigned int size)
557  {
558  // _read_line_bin is bufferised with the same buffer as textual
559  // protocols, so this function can be used for binary and text
560  // protocols.
561  return _read_line_bin(_socket, port, host, size);
562  }
563 
564  std::string NetSocket::readn(int& port, std::string& host, int timeout,
565  unsigned int size)
566  {
567  if (!size || size > _buffer.size())
568  _set_timeout(true, _socket, timeout);
569  // _read_line_bin is bufferised with the same buffer as textual
570  // protocols, so this function can be used for binary and text
571  // protocols.
572  return _read_line_bin(_socket, port, host, size);
573  }
574 
575  std::string NetSocket::readn(unsigned int size)
576  {
577  // _read_line_bin is bufferised with the same buffer as textual
578  // protocols, so this function can be used for binary and text
579  // protocols.
580  return _read_line_bin(_socket, size);
581  }
582 
583  std::string NetSocket::readn(int timeout, unsigned int size)
584  {
585  if (!size || size > _buffer.size())
586  _set_timeout(true, _socket, timeout);
587  // _read_line_bin is bufferised with the same buffer as textual
588  // protocols, so this function can be used for binary and text
589  // protocols.
590  return _read_line_bin(_socket, size);
591  }
592 }
void _write_str(int socket, const std::string &str, const std::string &host, int port) const
Write a string to a socket to a particular host (UDP) (when used with textual protocol) when there is...
Definition: netsocket.cc:400
Network namespace represent all networks connection.
Definition: localsocket.cc:32
void _connect(int socket, int port, const std::string &host) const
Connect to a hostname when connect libc function return a negative value.
Definition: netsocket.cc:186
#define SENDTO_FLAGS
Definition: socket.hh:48
virtual void writeto(const std::string &str, const std::string &host, int port)
function used to send a msg to a specific host (UDP)
Definition: netsocket.cc:502
void _write_str_bin(int socket, const std::string &str, const std::string &host, int port) const
Write a string to a socket to a particular host (UDP) (when used with binary protocol) when there is ...
Definition: netsocket.cc:446
std::string read()
function used by >> operator (read a string on current socket)
Definition: netsocket.cc:533
std::string _read_line(int socket)
Get a line from socket (when used with textual protocol) when there is no open socket when there is n...
Definition: netsocket.cc:261
This class is the top exception class used in libsocket.
#define HERE
This class represent an abstract socket connection (udp | tcp server | tcp client) ...
Definition: netsocket.hh:33
std::string readn(unsigned int size)
read a string from socket
Definition: netsocket.cc:575
std::string _get_ip(int port, int socket) const
Get Client Ip.
Definition: netsocket.cc:243
int _accept(int port, int server_socket) const
Wait for a client when accept libc function return a negative value.
Definition: netsocket.cc:211
int _bind(int port, const std::string &host)
Bind a UDP server when socket libc function return a negative value if the selected protocole is inco...
Definition: netsocket.cc:86