DCL 4.0
Loading...
Searching...
No Matches
Socket.cpp
Go to the documentation of this file.
1#include <dcl/Config.h>
2
3#include <string.h> // memset
4
5#if __DCL_WINDOWS
6 #include <winsock2.h>
7#else
8 #include <errno.h>
9 #include <sys/types.h>
10 #include <sys/ioctl.h> // ioctl
11 #include <sys/socket.h> // send, recv
12 #include <netdb.h> // gethostbyname
13 #include <unistd.h> // close
14 #include <stdlib.h> // alloca
15#endif
16
17#include <dcl/Charset.h>
18#include <dcl/Numeric.h>
19#include <dcl/Socket.h>
20
21#if !__DCL_WINDOWS
22 #include "__strumbs.h"
23#endif
24
25#if __DCL_DEBUG
26 #undef __THIS_FILE__
27 static const char_t __THIS_FILE__[] = __T("dcl/Socket.cpp");
28#endif
29
30#undef INVALID_SOCKET
31#if __DCL_WINDOWS
32 #define SOCKET_TYPE UINT_PTR
33 #define INVALID_SOCKET (UINT_PTR) -1
34 #define __ERRNO WSAGetLastError()
35#else
36 #define SOCKET_TYPE int
37 #define INVALID_HANDLE_VALUE -1
38 #define INVALID_SOCKET -1
39 #define closesocket(s) close(s)
40 #define ioctlsocket(s, cmd, argp) ioctl(s, cmd, argp)
41 #define __ERRNO errno
42#endif
43
44__DCL_BEGIN_NAMESPACE
45
47
48String Socket::toString() const
49{
50 StringBuilder r = className();
52 r += __T(" closed");
53 else {
54 if (!__path.isEmpty()) {
55 r += __T(" local ");
56 r += __path;
57 }
58
59 Addr addr;
60 socklen_t n = sizeof(addr);
61 if (!::getpeername((SOCKET_TYPE) __handle, (struct sockaddr*) &addr, &n)) {
62 String foreign = addr.toString();
63 if (!foreign.isEmpty()) {
64 if (!__path.isEmpty())
65 r += __T(",");
66 r += __T(" foreign ") + foreign;
67 }
68 }
69 }
70
71 return r;
72}
73
74void Socket::open(const String& _addr, uint16_t _port)
76{
77 if (__handle != INVALID_HANDLE_VALUE)
78 close();
79
80 Addr addr(_addr, _port);
81 connect(addr);
82}
83
84size_t Socket::available() const
86{
87 u_long n = 0;
88 if (ioctlsocket((SOCKET_TYPE) __handle, FIONREAD, &n))
89 throw new IOException(toString(), __ERRNO);
90
91 return (size_t)n;
92}
93
94size_t Socket::read(void* _buf, size_t _n)
96{
97 return recv(_buf, _n, 0);
98}
99
100size_t Socket::write(const void* _buf, size_t _n)
102{
103 return send(_buf, _n, 0);
104}
105
106Socket::Addr::Addr()
107{
108 memset((void*) this, 0, sizeof(Addr));
109}
110
111static void __init_inet_addr(Socket::Addr* _dest, const char* _addr, uint16_t _port)
112 __DCL_THROWS1(IOException*)
113{
114 if (*_addr != '\0') {
115 if (strchr(_addr, ':') &&
116 inet_pton(AF_INET6, _addr, &(_dest->sa_in6.sin6_addr)) > 0) {
117 _dest->sa_family = AF_INET6;
118 _dest->sa_in6.sin6_port = htons(_port);
119 return;
120 }
121 else if(inet_pton(AF_INET, _addr, &(_dest->sa_in.sin_addr)) > 0) {
122 _dest->sa_family = AF_INET;
123 _dest->sa_in.sin_port = htons(_port);
124 return;
125 }
126 }
127
128 struct hostent* ent = gethostbyname(_addr);
129 if (ent) {
130#if 0
131 __DCL_TRACE4(__T("name[%hs], aliases[%hs], type[%d], length[%d]\n"),
132 ent->h_name ? ent->h_name : "(null)",
133 ent->h_aliases ? ent->h_aliases[0] : "(null)",
134 ent->h_addrtype, ent->h_length
135 );
136#endif
137 _dest->sa_family = ent->h_addrtype;
138 switch (_dest->sa_family) {
139 case AF_INET: {
140#if 0
141 {
142 char** list = ent->h_addr_list;
143 for (int i = 0; list[i] != NULL; i++) {
144 printf("[%d] [", i);
145 for (int j = 0; j < ent->h_length; j++) {
146 if (j > 0)
147 printf(".");
148 printf("%u", (unsigned char) list[i][j]);
149 }
150 printf("]\n");
151 }
152 }
153#endif
154 _dest->sa_in.sin_addr.s_addr = *(u_long*) ent->h_addr_list[0];
155 _dest->sa_in.sin_port = htons(_port);
156 break;
157 }
158 case AF_INET6: {
159 memcpy(&(_dest->sa_in6), ent->h_addr_list[0], ent->h_length);
160 _dest->sa_in6.sin6_port = htons(_port);
161 break;
162 }
163 default: {
164 __DCL_ASSERT(false);
165 }
166 }
167 return;
168 }
169
170 AsciiDecoder dec;
171 String s = dec.decode(_addr);
172 throw new IOException(s,
173#if __DCL_WINDOWS
174 WSAEAFNOSUPPORT
175#else
176 EAFNOSUPPORT
177#endif
178 );
179}
180
181Socket::Addr::Addr(const char *_addr, uint16_t _port)
182 __DCL_THROWS1(IOException*)
183{
184 __DCL_ASSERT(_addr != NULL);
185 memset((void*) this, 0, sizeof(Addr));
186
187 __init_inet_addr(this, _addr, _port);
188}
189
190Socket::Addr::Addr(const String& _addr, uint16_t _port)
191 __DCL_THROWS1(IOException*)
192{
193 memset((void*) this, 0, sizeof(Addr));
194
195 AsciiEncoder enc;
196 ByteString addr;
197 try {
198 addr = enc.encode(_addr);
199 }
200 catch (CharsetConvertException* cause) {
201 throw new IOException(_addr, cause);
202 }
203
204 __init_inet_addr(this, addr, _port);
205}
206
207#if !__DCL_WINDOWS
208Socket::Addr::Addr(const char* _path)
209 __DCL_THROWS1(IOException*)
210{
211 memset((void*) this, 0, sizeof(Addr));
212
213 __DCL_ASSERT(_path != NULL);
214 size_t n = ByteString::length(_path);
215 if (n > sizeof(sa_un.sun_path))
216 {
217
218 throw new IOException(AsciiDecoder::decode(_path, n), ENAMETOOLONG);
219 }
220
221 sa_un.sun_family = AF_UNIX;
222 strncpy(sa_un.sun_path, _path, n);
223}
224
225Socket::Addr::Addr(const String& _path)
226 __DCL_THROWS1(IOException*)
227{
228 memset((void*) this, 0, sizeof(Addr));
229
230 __DCL_ASSERT(!_path.isEmpty());
231 STRTOMBS(_path, mbs)
232 else
233 throw new IOException(_path, EILSEQ);
234
235 if (nmbs > sizeof(sa_un.sun_path))
236 throw new IOException(_path, ENAMETOOLONG);
237
238 sa_un.sun_family = AF_UNIX;
239 strncpy(sa_un.sun_path, mbs, nmbs);
240}
241#endif
242
243String Socket::Addr::toString() const
244{
245 char buf[512];
246
247 switch (sa_family) {
248#if !__DCL_WINDOWS
249 case AF_UNIX: {
250 strncpy(buf, sa_un.sun_path, __countof(sa_un.sun_path, char));
251 AsciiDecoder dec;
252 return dec.decode(buf);
253 break;
254 }
255#endif
256 case AF_INET: {
257 if (inet_ntop(AF_INET, (void*) &(sa_in.sin_addr), buf, sizeof(buf))) {
258 AsciiDecoder dec;
259 StringBuilder r = dec.decode(buf);
260 r += __T(":");
261 r += UInteger::toString(ntohs(sa_in.sin_port), 10);
262 return r;
263 }
264 break;
265 }
266 case AF_INET6: {
267 if (inet_ntop(AF_INET6, (void*) &(sa_in6.sin6_addr), buf, sizeof(buf))) {
268 AsciiDecoder dec;
269 StringBuilder r = dec.decode(buf);
270 if (sa_in6.sin6_flowinfo) {
271 r += __T("%");
272 r += UInteger::toString(sa_in6.sin6_flowinfo, 10);
273 }
274 r += __T(":");
275 r += UInteger::toString(ntohs(sa_in6.sin6_port), 10);
276 return r;
277 }
278 break;
279 }
280 default : {
281 __DCL_ASSERT(false);
282 }
283 }
284
285 return String(__T("Invalid !!"));
286}
287
288void Socket::bind(const Addr& _addr, int _type, int _protocol, bool _reuse)
289 __DCL_THROWS1(IOException*)
290{
292 create(_addr.sa_family, _type, _protocol);
293
294 socklen_t n = sizeof(_addr);
295 switch (_addr.sa_family) {
296#if !__DCL_WINDOWS
297 case AF_UNIX: {
298 n = sizeof(_addr.sa_un);
299 break;
300 }
301#endif
302 case AF_INET: {
303 n = sizeof(_addr.sa_in);
304 break;
305 }
306 case AF_INET6: {
307 n = sizeof(_addr.sa_in6);
308 break;
309 }
310 default: {
311 __DCL_ASSERT(false);
312 }
313 }
314
315 if (_reuse) {
316#if __DCL_WINDOWS
317 BOOL reuse = TRUE;
318 if (::setsockopt((SOCKET_TYPE) __handle,
319 SOL_SOCKET, SO_REUSEADDR, (const char*) &reuse, sizeof(reuse)
320 ))
321 throw new IOException(__path, WSAGetLastError());
322#else
323 int reuse = 1;
324 if (::setsockopt((SOCKET_TYPE) __handle,
325 SOL_SOCKET, SO_REUSEADDR, (const void*) &reuse, sizeof(reuse)))
326 throw new IOException(__path, errno);
327#endif
328 }
329
330 bind((const sockaddr*) &_addr, n);
331}
332
333void Socket::accept(Socket& _r)
334 __DCL_THROWS1(IOException*)
335{
336 Addr addr;
337 socklen_t n = sizeof(addr);
338 accept(_r, (struct sockaddr*) &addr, &n);
339}
340
341void Socket::connect(const Addr& _addr)
342 __DCL_THROWS1(IOException*)
343{
345 create(_addr.sa_family, SOCK_STREAM, IPPROTO_TCP);
346
347 socklen_t n = sizeof(_addr);
348 switch (_addr.sa_family) {
349#if !__DCL_WINDOWS
350 case AF_UNIX: {
351 n = sizeof(_addr.sa_un);
352 break;
353 }
354#endif
355 case AF_INET: {
356 n = sizeof(_addr.sa_in);
357 break;
358 }
359 case AF_INET6: {
360 n = sizeof(_addr.sa_in6);
361 break;
362 }
363 default: {
364 __DCL_ASSERT(false);
365 }
366 }
367
368 connect((const sockaddr*) &_addr, n);
369}
370
371socklen_t Socket::getsockname(Addr& _addr)
372 __DCL_THROWS1(IOException*)
373{
375 socklen_t n = sizeof(_addr);
376 if (::getsockname((SOCKET_TYPE) __handle, (struct sockaddr*) &_addr, &n) == -1)
377 throw new IOException(toString(), __ERRNO);
378 return n;
379}
380
381socklen_t Socket::getpeername(Addr& _addr)
382 __DCL_THROWS1(IOException*)
383{
385 socklen_t n = sizeof(_addr);
386 if (::getpeername((SOCKET_TYPE) __handle, (struct sockaddr*) &_addr, &n) == -1)
387 throw new IOException(toString(), __ERRNO);
388 return n;
389}
390
391Socket::Socket()
392{
393// File::__handle = INVALID_HANDLE_VALUE;
394#if __DCL_WINDOWS
395 __waitEvent = WSA_INVALID_EVENT;
396#endif
397}
398
399Socket::Socket(const String& _addr, uint16_t _port)
400 __DCL_THROWS1(IOException*)
401{
402// File::__handle = INVALID_HANDLE_VALUE;
403#if __DCL_WINDOWS
404 __waitEvent = WSA_INVALID_EVENT;
405#endif
406 open(_addr, _port);
407}
408
409
410Socket::~Socket()
411{
413 try {
414 close();
415 }
416 catch (IOException* cause) {
417 __DCL_TRACE1(__T("Error! Socket::~Socket %ls\n"), cause->toString().data());
418 cause->destroy();
419 }
420 }
421#if __DCL_WINDOWS
422 if (__waitEvent != WSA_INVALID_EVENT) {
423 WSACloseEvent(__waitEvent);
424 __waitEvent = WSA_INVALID_EVENT;
425 }
426#endif
427}
428
429void Socket::close()
430 __DCL_THROWS1(IOException*)
431{
433
435 String path = __path;
437 __path.clear();
438
440 throw new IOException(__path, __ERRNO);
441}
442
443#if defined(_MSC_VER) && !defined(__DCL_CORE_EXPORTS)
444 #pragma optimize ( "", off )
445 #pragma warning ( push )
446 #pragma warning ( disable : 4748 )
447#endif
448
449void Socket::create(int _domain, int _type, int _protocol)
450 __DCL_THROWS1(IOException*)
451{
453
454 SOCKET_TYPE handle = ::socket(_domain, _type, _protocol);
455 if (handle == INVALID_SOCKET)
456 throw new IOException(toString(), __ERRNO);
457 __handle = (HandleType) handle;
458}
459
460void Socket::setNonblock()
461 __DCL_THROWS1(IOException*)
462{
464
465 unsigned long u = 1;
466 if (::ioctlsocket((SOCKET_TYPE) __handle, FIONBIO, &u))
467 throw new IOException(toString(), __ERRNO);
468}
469
470void Socket::bind(const struct sockaddr* _my_addr, socklen_t _addrlen)
471 __DCL_THROWS1(IOException*)
472{
474
475 if (::bind((SOCKET_TYPE) __handle, _my_addr, _addrlen))
476 throw new IOException(toString(), __ERRNO);
477
478 Addr raddr;
479 getsockname(raddr);
480 __path = raddr.toString();
481}
482
483void Socket::listen(unsigned _backlog)
484 __DCL_THROWS1(IOException*)
485{
487
488 if (::listen((SOCKET_TYPE) __handle, _backlog))
489 throw new IOException(toString(), __ERRNO);
490}
491
492void Socket::accept(Socket& r, struct sockaddr* _addr, socklen_t* _addrlen)
493 __DCL_THROWS1(IOException*)
494{
497 __DCL_ASSERT_PARAM(_addr != NULL && _addrlen != NULL);
498
499 SOCKET_TYPE handle = ::accept((SOCKET_TYPE) __handle, _addr, _addrlen);
500 if (handle == INVALID_SOCKET)
501 throw new IOException(toString(), __ERRNO);
502
503 r.__handle = (HandleType) handle;
504 Addr raddr;
505 r.getsockname(raddr);
506 r.__path = raddr.toString();
507}
508
509void Socket::connect(const sockaddr* _serv_addr, socklen_t _addrlen)
510 __DCL_THROWS1(IOException*)
511{
513
514 if (::connect((SOCKET_TYPE) __handle, _serv_addr, _addrlen))
515 throw new IOException(toString(), __ERRNO);
516
517 Addr raddr;
518 getsockname(raddr);
519 __path = raddr.toString();
520}
521
522size_t Socket::send(const void* _buf, size_t _n, int _flags)
523 __DCL_THROWS1(IOException*)
524{
526 __DCL_ASSERT_PARAM(_buf != NULL);
527
528#if __DCL_WINDOWS
529 int n = ::send((SOCKET_TYPE) __handle, (const char*) _buf, _n, _flags);
530 if (n == SOCKET_ERROR)
531 {
532 // 소켓이 nonblocking으로 표시되었고 오퍼레이션이 블록되었다.
533 if (WSAGetLastError() == WSAEWOULDBLOCK)
534 return 0;
535 else
536 throw new IOException(toString(), WSAGetLastError());
537 }
538
539#else
540 int n = ::send((SOCKET_TYPE) __handle, _buf, _n, _flags);
541 if (n == -1)
542 {
543 // 소켓이 nonblocking으로 표시되었고 오퍼레이션이 블록되었다.
544 if (errno == EAGAIN || errno == EWOULDBLOCK)
545 return 0;
546 else
547 throw new IOException(toString(), errno);
548 }
549
550#endif
551 return (size_t) n;
552}
553
554size_t Socket::recv(void* _buf, size_t _n, int _flags)
555 __DCL_THROWS1(IOException*)
556{
558 __DCL_ASSERT_PARAM(_buf != NULL);
559
560#if __DCL_WINDOWS
561 int n = ::recv((SOCKET_TYPE) __handle, (char*) _buf, _n, _flags);
562 if (n == SOCKET_ERROR)
563 {
564 // 소켓이 nonblocking으로 표시되었고 오퍼레이션이 블록되었다.
565 if (WSAGetLastError() == WSAEWOULDBLOCK)
566 return 0;
567 else
568 throw new IOException(toString(), WSAGetLastError());
569 }
570
571#else
572 int n = ::recv((SOCKET_TYPE) __handle, _buf, _n, _flags);
573 if (n == -1)
574 {
575 // 소켓이 nonblocking으로 표시되었고 오퍼레이션이 블록되었다.
576 if (errno == EAGAIN || errno == EWOULDBLOCK)
577 return 0;
578 else
579 throw new IOException(toString(), errno);
580 }
581
582#endif
583 return (size_t) n;
584}
585
586#if defined(_MSC_VER) && !defined(__DCL_CORE_EXPORTS)
587 #pragma warning ( pop )
588 #pragma optimize ( "", on )
589#endif
590
591bool Socket::onEvent(short _revents, PollThread* _pPollThread)
593{
594 // Nothing
595 return true;
596}
597
598__DCL_END_NAMESPACE
#define STRTOMBS(str, mbs)
Definition __strumbs.h:25
#define __THIS_FILE__
Definition _trace.h:14
#define NULL
Definition Config.h:340
#define __countof(array, type)
Definition Config.h:365
wchar_t char_t
Definition Config.h:275
#define __DCL_THROWS1(e)
Definition Config.h:167
#define INVALID_HANDLE_VALUE
Definition Dir.cpp:31
int BOOL
#define TRUE
#define __DCL_TRACE1(fmt, arg1)
Definition Object.h:376
#define __DCL_ASSERT_PARAM(expr)
Definition Object.h:384
#define __DCL_ASSERT(expr)
Definition Object.h:371
#define __DCL_TRACE4(fmt, arg1, arg2, arg3, arg4)
Definition Object.h:379
#define IMPLEMENT_CLASSINFO(class_name, base_class_name)
Definition Object.h:228
#define __T(str)
Definition Object.h:44
#define __DCL_ASSERT_HANDLE(expr)
Definition Object.h:383
ByteString r
ByteBuffer * buf
_r
Definition SQLField.cpp:260
void CharsetConvertException *size_t n
Definition SQLField.cpp:253
#define __ERRNO
Definition Socket.cpp:41
#define ioctlsocket(s, cmd, argp)
Definition Socket.cpp:40
#define INVALID_SOCKET
Definition Socket.cpp:38
#define closesocket(s)
Definition Socket.cpp:39
#define SOCKET_TYPE
Definition Socket.cpp:36
static String decode(const char *_mbs, size_t _mbslen=(size_t) -1)
virtual void destroy()
Definition Exception.cpp:74
HandleType handle() const
Definition File.h:242
HandleType __handle
Definition File.h:251
virtual void close() __DCL_THROWS1(IOException *)
Definition File.cpp:363
String __path
Definition File.h:250
virtual String toString() const
const String & path() const
Definition File.h:247
virtual size_t available() const __DCL_THROWS1(IOException *)
Definition File.cpp:401
virtual String toString() const
String className() const
Definition Object.cpp:163
friend class PollThread
Definition PollAble.h:38
virtual bool onEvent(short _revents, PollThread *_pPollThread) __DCL_THROWS1(IOException *)
Definition Socket.cpp:591
String toString(unsigned _base=10) const
Definition Numeric.inl:54