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