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
27namespace 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)
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)
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,
486 (const struct sockaddr*)&addr, sizeof(_addr));
487#ifdef IPV6_ENABLED
488 else
489 res = sendto(socket, buf + count, str.size() + 2 - count,
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}
This class is the top exception class used in libsocket.
This class represent an abstract socket connection (udp | tcp server | tcp client)
Definition: netsocket.hh:34
int _bind(int port, const std::string &host)
Bind a UDP server.
Definition: netsocket.cc:86
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
std::string _read_line(int socket)
Get a line from socket (when used with textual protocol)
Definition: netsocket.cc:261
std::string _get_ip(int port, int socket) const
Get Client Ip.
Definition: netsocket.cc:243
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)
Definition: netsocket.cc:446
std::string readn(unsigned int size)
read a string from socket
Definition: netsocket.cc:575
void _connect(int socket, int port, const std::string &host) const
Connect to a hostname.
Definition: netsocket.cc:186
struct sockaddr_in _get_addr(int port) const
internal function (construct a sockaddr)
Definition: netsocket.cc:61
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)
Definition: netsocket.cc:400
int _accept(int port, int server_socket) const
Wait for a client.
Definition: netsocket.cc:211
virtual std::string _read_line_bin(int socket, int &port, std::string &host, unsigned int pkg_size)=0
Get a line from socket and store client hostname and port in port and host variable (when used with b...
std::string read()
function used by >> operator (read a string on current socket)
Definition: netsocket.cc:533
void _set_timeout(bool enable, int socket, int timeout)
set a timeout on a socket
Definition: socket.cc:272
std::string _buffer
Definition: socket.hh:202
struct sockaddr_in _addr
Definition: socket.hh:195
bool _check_answer(int res, std::string &str)
return the content of the buffer is there is
Definition: socket.hxx:28
unsigned _state_timeout
Definition: socket.hh:192
SOCKET_KIND _kind
Definition: socket.hh:190
SOCKET_VERSION _version
Definition: socket.hh:191
bool _update_buffer(std::pair< int, int > &delim, int &i, std::string &str)
look delimiter and remove delimiter at begining of buffer if needed
Definition: socket.hxx:45
PROTO_KIND _proto_kind
Definition: socket.hh:199
Network namespace represent all networks connection.
Definition: localsocket.cc:33
@ V4
Definition: socket.hh:87
@ TCP
Definition: socket.hh:80
@ UDP
Definition: socket.hh:81
@ binary
Definition: socket.hh:75
#define SENDTO_FLAGS
Definition: socket.hh:48
#define HERE