source: filezilla/trunk/fuentes/src/engine/socket.cpp @ 130

Last change on this file since 130 was 130, checked in by jrpelegrina, 4 years ago

First release to xenial

File size: 37.3 KB
Line 
1#include <wx/defs.h>
2#ifdef __WXMSW__
3  #ifndef NOMINMAX
4  #define NOMINMAX
5  #endif
6  // MinGW needs this for getaddrinfo
7  #if defined(_WIN32_WINNT)
8    #if _WIN32_WINNT < 0x0600
9      #undef _WIN32_WINNT
10      #define _WIN32_WINNT 0x0600
11    #endif
12  #else
13    #define _WIN32_WINNT 0x0600
14  #endif
15  #include <winsock2.h>
16  #include <ws2tcpip.h>
17#endif
18#include <filezilla.h>
19#include "mutex.h"
20#include "socket.h"
21#ifndef __WXMSW__
22  #define mutex mutex_override // Sadly on some platforms system headers include conflicting names
23  #include <sys/types.h>
24  #include <sys/socket.h>
25  #include <netdb.h>
26  #include <fcntl.h>
27  #include <arpa/inet.h>
28  #include <netinet/in.h>
29  #include <netinet/tcp.h>
30  #if !defined(MSG_NOSIGNAL) && !defined(SO_NOSIGPIPE)
31    #include <signal.h>
32  #endif
33  #undef mutex
34#endif
35
36// Fixups needed on FreeBSD
37#if !defined(EAI_ADDRFAMILY) && defined(EAI_FAMILY)
38  #define EAI_ADDRFAMILY EAI_FAMILY
39#endif
40
41#ifndef AI_NUMERICSERV
42#define AI_NUMERICSERV 0
43#endif
44
45// Union for strict aliasing-safe casting between
46// the different address types
47union sockaddr_u
48{
49        struct sockaddr_storage storage;
50        struct sockaddr sockaddr;
51        struct sockaddr_in in4;
52        struct sockaddr_in6 in6;
53};
54
55#define WAIT_CONNECT 0x01
56#define WAIT_READ        0x02
57#define WAIT_WRITE       0x04
58#define WAIT_ACCEPT  0x08
59#define WAIT_CLOSE       0x10
60#define WAIT_EVENTCOUNT 5
61
62class CSocketThread;
63namespace {
64static std::vector<CSocketThread*> waiting_socket_threads;
65static mutex waiting_socket_threads_mutex{false};
66};
67
68struct socket_event_type;
69typedef CEvent<socket_event_type> CInternalSocketEvent;
70
71void RemoveSocketEvents(CEventHandler * handler, CSocketEventSource const* const source)
72{
73        auto socketEventFilter = [&](CEventLoop::Events::value_type const& ev) -> bool {
74                if (ev.first != handler) {
75                        return false;
76                }
77                else if (ev.second->derived_type() == CSocketEvent::type()) {
78                        return std::get<0>(static_cast<CSocketEvent const&>(*ev.second).v_) == source;
79                }
80                else if (ev.second->derived_type() == CHostAddressEvent::type()) {
81                        return std::get<0>(static_cast<CHostAddressEvent const&>(*ev.second).v_) == source;
82                }
83                return false;
84        };
85
86        handler->event_loop_.FilterEvents(socketEventFilter);
87}
88
89void ChangeSocketEventHandler(CEventHandler * oldHandler, CEventHandler * newHandler, CSocketEventSource const* const source)
90{
91        if (!oldHandler)
92                return;
93        if (oldHandler == newHandler) {
94                return;
95        }
96
97        if (!newHandler) {
98                RemoveSocketEvents(oldHandler, source);
99        }
100        else {
101                auto socketEventFilter = [&](CEventLoop::Events::value_type & ev) -> bool {
102                        if (ev.first == oldHandler) {
103                                if (ev.second->derived_type() == CSocketEvent::type()) {
104                                        if (std::get<0>(static_cast<CSocketEvent const&>(*ev.second).v_) == source) {
105                                                ev.first = newHandler;
106                                        }
107                                }
108                                else if (ev.second->derived_type() == CHostAddressEvent::type()) {
109                                        if (std::get<0>(static_cast<CHostAddressEvent const&>(*ev.second).v_) == source) {
110                                                ev.first = newHandler;
111                                        }
112                                }
113                        }
114                        return false;
115                };
116
117                oldHandler->event_loop_.FilterEvents(socketEventFilter);
118        }
119}
120
121namespace {
122#ifdef __WXMSW__
123static int ConvertMSWErrorCode(int error)
124{
125        switch (error)
126        {
127        case WSAECONNREFUSED:
128                return ECONNREFUSED;
129        case WSAECONNABORTED:
130                return ECONNABORTED;
131        case WSAEINVAL:
132                return EAI_BADFLAGS;
133        case WSANO_RECOVERY:
134                return EAI_FAIL;
135        case WSAEAFNOSUPPORT:
136                return EAI_FAMILY;
137        case WSA_NOT_ENOUGH_MEMORY:
138                return EAI_MEMORY;
139        case WSANO_DATA:
140                return EAI_NODATA;
141        case WSAHOST_NOT_FOUND:
142                return EAI_NONAME;
143        case WSATYPE_NOT_FOUND:
144                return EAI_SERVICE;
145        case WSAESOCKTNOSUPPORT:
146                return EAI_SOCKTYPE;
147        case WSAEWOULDBLOCK:
148                return EAGAIN;
149        case WSAEMFILE:
150                return EMFILE;
151        case WSAEINTR:
152                return EINTR;
153        case WSAEFAULT:
154                return EFAULT;
155        case WSAEACCES:
156                return EACCES;
157        case WSAETIMEDOUT:
158                return ETIMEDOUT;
159        case WSAECONNRESET:
160                return ECONNRESET;
161        case WSAEHOSTDOWN:
162                return EHOSTDOWN;
163        case WSAENETUNREACH:
164                return ENETUNREACH;
165        case WSAEADDRINUSE:
166                return EADDRINUSE;
167        default:
168                return error;
169        }
170}
171
172int GetLastSocketError()
173{
174        return ConvertMSWErrorCode(WSAGetLastError());
175}
176#else
177inline int GetLastSocketError() { return errno; }
178#endif
179
180#ifdef ERRORCODETEST
181class CErrorCodeTest
182{
183public:
184        CErrorCodeTest()
185        {
186                int errors[] = {
187                        0
188                };
189                for (int i = 0; errors[i]; ++i) {
190#ifdef __WXMSW__
191                        int code = ConvertMSWErrorCode(errors[i]);
192#else
193                        int code = errors[i];
194#endif
195                        if (CSocket::GetErrorDescription(code).Len() < 15)
196                                wxMessageBoxEx(CSocket::GetErrorDescription(code));
197                }
198
199        }
200};
201#endif
202}
203
204class CSocketThread final : protected wxThread
205{
206        friend class CSocket;
207public:
208        CSocketThread()
209                : wxThread(wxTHREAD_JOINABLE), m_sync(false)
210        {
211#ifdef __WXMSW__
212                m_sync_event = WSA_INVALID_EVENT;
213#else
214                m_pipe[0] = -1;
215                m_pipe[1] = -1;
216#endif
217                for (int i = 0; i < WAIT_EVENTCOUNT; ++i) {
218                        m_triggered_errors[i] = 0;
219                }
220        }
221
222        virtual ~CSocketThread()
223        {
224#ifdef __WXMSW__
225                if (m_sync_event != WSA_INVALID_EVENT)
226                        WSACloseEvent(m_sync_event);
227#else
228                if (m_pipe[0] != -1)
229                        close(m_pipe[0]);
230                if (m_pipe[1] != -1)
231                        close(m_pipe[1]);
232#endif
233        }
234
235        void SetSocket(CSocket* pSocket)
236        {
237                scoped_lock l(m_sync);
238                SetSocket(pSocket, l);
239        }
240
241        void SetSocket(CSocket* pSocket, scoped_lock const&)
242        {
243                m_pSocket = pSocket;
244
245                m_host.clear();
246                m_port.clear();
247
248                m_waiting = 0;
249        }
250
251        int Connect(wxString const& bind)
252        {
253                wxASSERT(m_pSocket);
254
255                auto const hostBuf = m_pSocket->m_host.mb_str();
256                auto const bindBuf = bind.mb_str();
257                if (!hostBuf || !bindBuf) {
258                        m_bind.clear();
259                        m_host.clear();
260                        m_port.clear();
261                        return EINVAL;
262                }
263                m_host = hostBuf;
264                m_bind = bindBuf;
265
266                // Connect method of CSocket ensures port is in range
267                char tmp[7];
268                sprintf(tmp, "%u", m_pSocket->m_port);
269                tmp[5] = 0;
270                m_port = tmp;
271
272                Start();
273
274                return 0;
275        }
276
277        int Start()
278        {
279                if (m_started) {
280                        scoped_lock l(m_sync);
281                        wxASSERT(m_threadwait);
282                        m_waiting = 0;
283                        WakeupThread(l);
284                        return 0;
285                }
286                m_started = true;
287#ifdef __WXMSW__
288                if (m_sync_event == WSA_INVALID_EVENT)
289                        m_sync_event = WSACreateEvent();
290                if (m_sync_event == WSA_INVALID_EVENT)
291                        return 1;
292#else
293                if (m_pipe[0] == -1) {
294                        if (pipe(m_pipe))
295                                return errno;
296                }
297#endif
298
299                int res = Create();
300                if (res != wxTHREAD_NO_ERROR)
301                        return 1;
302
303                Run();
304
305                return 0;
306        }
307
308        // Cancels select or idle wait
309        void WakeupThread()
310        {
311                scoped_lock l(m_sync);
312                WakeupThread(l);
313        }
314
315        void WakeupThread(scoped_lock & l)
316        {
317                if (!m_started || m_finished) {
318                        return;
319                }
320
321                if (m_threadwait) {
322                        m_threadwait = false;
323                        m_condition.signal(l);
324                        return;
325                }
326
327#ifdef __WXMSW__
328                WSASetEvent(m_sync_event);
329#else
330                char tmp = 0;
331
332                int ret;
333                do {
334                        ret = write(m_pipe[1], &tmp, 1);
335                } while (ret == -1 && errno == EINTR);
336#endif
337        }
338
339protected:
340        static int CreateSocketFd(addrinfo const& addr)
341        {
342                int fd;
343#if defined(SOCK_CLOEXEC) && !defined(__WXMSW__)
344                fd = socket(addr.ai_family, addr.ai_socktype | SOCK_CLOEXEC, addr.ai_protocol);
345                if (fd == -1 && errno == EINVAL)
346#endif
347                {
348                        fd = socket(addr.ai_family, addr.ai_socktype, addr.ai_protocol);
349                }
350
351                if (fd != -1) {
352#if defined(SO_NOSIGPIPE) && !defined(MSG_NOSIGNAL)
353                        // We do not want SIGPIPE if writing to socket.
354                        const int value = 1;
355                        setsockopt(fd, SOL_SOCKET, SO_NOSIGPIPE, &value, sizeof(int));
356#endif
357                        CSocket::SetNonblocking(fd);
358                }
359
360                return fd;
361        }
362
363        static void CloseSocketFd(int& fd)
364        {
365                if (fd != -1) {
366        #ifdef __WXMSW__
367                        closesocket(fd);
368        #else
369                        close(fd);
370        #endif
371                        fd = -1;
372                }
373        }
374
375        int TryConnectHost(addrinfo & addr, sockaddr_u const& bindAddr, scoped_lock & l)
376        {
377                if (m_pSocket->m_pEvtHandler) {
378                        m_pSocket->m_pEvtHandler->SendEvent<CHostAddressEvent>(m_pSocket, CSocket::AddressToString(addr.ai_addr, addr.ai_addrlen));
379                }
380
381                int fd = CreateSocketFd(addr);
382                if (fd == -1) {
383                        if (m_pSocket->m_pEvtHandler) {
384                                m_pSocket->m_pEvtHandler->SendEvent<CSocketEvent>(m_pSocket, addr.ai_next ? SocketEventType::connection_next : SocketEventType::connection, GetLastSocketError());
385                        }
386
387                        return 0;
388                }
389
390                if (bindAddr.sockaddr.sa_family != AF_UNSPEC && bindAddr.sockaddr.sa_family == addr.ai_family) {
391                        (void)bind(fd, &bindAddr.sockaddr, sizeof(bindAddr));
392                }
393
394                CSocket::DoSetFlags(fd, m_pSocket->m_flags, m_pSocket->m_flags);
395                CSocket::DoSetBufferSizes(fd, m_pSocket->m_buffer_sizes[0], m_pSocket->m_buffer_sizes[1]);
396
397                int res = connect(fd, addr.ai_addr, addr.ai_addrlen);
398                if (res == -1) {
399#ifdef __WXMSW__
400                        // Map to POSIX error codes
401                        int error = WSAGetLastError();
402                        if (error == WSAEWOULDBLOCK)
403                                res = EINPROGRESS;
404                        else
405                                res = ConvertMSWErrorCode(WSAGetLastError());
406#else
407                        res = errno;
408#endif
409                }
410
411                if (res == EINPROGRESS) {
412
413                        m_pSocket->m_fd = fd;
414
415                        bool wait_successful;
416                        do {
417                                wait_successful = DoWait(WAIT_CONNECT, l);
418                                if ((m_triggered & WAIT_CONNECT))
419                                        break;
420                        } while (wait_successful);
421
422                        if (!wait_successful) {
423                                CloseSocketFd(fd);
424                                if (m_pSocket)
425                                        m_pSocket->m_fd = -1;
426                                return -1;
427                        }
428                        m_triggered &= ~WAIT_CONNECT;
429
430                        res = m_triggered_errors[0];
431                }
432
433                if (res) {
434                        if (m_pSocket->m_pEvtHandler) {
435                                m_pSocket->m_pEvtHandler->SendEvent<CSocketEvent>(m_pSocket, addr.ai_next ? SocketEventType::connection_next : SocketEventType::connection, res);
436                        }
437
438                        CloseSocketFd(fd);
439                        m_pSocket->m_fd = -1;
440                }
441                else {
442                        m_pSocket->m_fd = fd;
443                        m_pSocket->m_state = CSocket::connected;
444
445                        if (m_pSocket->m_pEvtHandler) {
446                                m_pSocket->m_pEvtHandler->SendEvent<CSocketEvent>(m_pSocket, SocketEventType::connection, 0);
447                        }
448
449                        // We're now interested in all the other nice events
450                        m_waiting |= WAIT_READ | WAIT_WRITE;
451
452                        return 1;
453                }
454
455                return 0;
456        }
457
458        // Only call while locked
459        bool DoConnect(scoped_lock & l)
460        {
461                if (m_host.empty() || m_port.empty()) {
462                        m_pSocket->m_state = CSocket::closed;
463                        return false;
464                }
465
466                std::string host, port, bind;
467                std::swap(host, m_host);
468                std::swap(port, m_port);
469                std::swap(bind, m_bind);
470
471                sockaddr_u bindAddr{};
472
473                if (!bind.empty()) {
474                        // Convert bind address
475                        addrinfo bind_hints{};
476                        bind_hints.ai_flags = AI_NUMERICHOST | AI_NUMERICSERV | AI_PASSIVE;
477                        bind_hints.ai_socktype = SOCK_STREAM;
478                        addrinfo *bindAddressList{};
479                        int res = getaddrinfo(bind.empty() ? 0 : bind.c_str(), "0", &bind_hints, &bindAddressList);
480                        if (!res && bindAddressList) {
481                                if (bindAddressList->ai_addr) {
482                                        memcpy(&bindAddr.storage, bindAddressList->ai_addr, bindAddressList->ai_addrlen);
483                                }
484                                freeaddrinfo(bindAddressList);
485                        }
486                }
487
488                addrinfo hints{};
489                hints.ai_family = m_pSocket->m_family;
490
491                l.unlock();
492
493                hints.ai_socktype = SOCK_STREAM;
494#ifdef AI_IDN
495                hints.ai_flags |= AI_IDN;
496#endif
497
498                addrinfo *addressList{};
499                int res = getaddrinfo(host.c_str(), port.c_str(), &hints, &addressList);
500
501                l.lock();
502
503                if (ShouldQuit()) {
504                        if (!res && addressList)
505                                freeaddrinfo(addressList);
506                        if (m_pSocket)
507                                m_pSocket->m_state = CSocket::closed;
508                        return false;
509                }
510
511                // If state isn't connecting, Close() was called.
512                // If m_pHost is set, Close() was called and Connect()
513                // afterwards, state is back at connecting.
514                // In either case, we need to abort this connection attempt.
515                if (m_pSocket->m_state != CSocket::connecting || !m_host.empty()) {
516                        if (!res && addressList)
517                                freeaddrinfo(addressList);
518                        return false;
519                }
520
521                if (res) {
522#ifdef __WXMSW__
523                        res = ConvertMSWErrorCode(res);
524#endif
525
526                        if (m_pSocket->m_pEvtHandler) {
527                                m_pSocket->m_pEvtHandler->SendEvent<CSocketEvent>(m_pSocket, SocketEventType::connection, res);
528                        }
529                        m_pSocket->m_state = CSocket::closed;
530
531                        return false;
532                }
533
534                for (addrinfo *addr = addressList; addr; addr = addr->ai_next) {
535                        res = TryConnectHost(*addr, bindAddr, l);
536                        if (res == -1) {
537                                freeaddrinfo(addressList);
538                                if (m_pSocket)
539                                        m_pSocket->m_state = CSocket::closed;
540                                return false;
541                        }
542                        else if (res) {
543                                freeaddrinfo(addressList);
544                                return true;
545                        }
546                }
547                freeaddrinfo(addressList);
548
549                if (m_pSocket->m_pEvtHandler) {
550                        m_pSocket->m_pEvtHandler->SendEvent<CSocketEvent>(m_pSocket, SocketEventType::connection, ECONNABORTED);
551                }
552                m_pSocket->m_state = CSocket::closed;
553
554                return false;
555        }
556
557        bool ShouldQuit() const
558        {
559                return m_quit || !m_pSocket;
560        }
561
562        // Call only while locked
563        bool DoWait(int wait, scoped_lock & l)
564        {
565                m_waiting |= wait;
566
567                for (;;) {
568#ifdef __WXMSW__
569                        int wait_events = FD_CLOSE;
570                        if (m_waiting & WAIT_CONNECT)
571                                wait_events |= FD_CONNECT;
572                        if (m_waiting & WAIT_READ)
573                                wait_events |= FD_READ;
574                        if (m_waiting & WAIT_WRITE)
575                                wait_events |= FD_WRITE;
576                        if (m_waiting & WAIT_ACCEPT)
577                                wait_events |= FD_ACCEPT;
578                        if (m_waiting & WAIT_CLOSE)
579                                wait_events |= FD_CLOSE;
580                        WSAEventSelect(m_pSocket->m_fd, m_sync_event, wait_events);
581                        l.unlock();
582                        WSAWaitForMultipleEvents(1, &m_sync_event, false, WSA_INFINITE, false);
583
584                        l.lock();
585                        if (ShouldQuit()) {
586                                return false;
587                        }
588
589                        WSANETWORKEVENTS events;
590                        int res = WSAEnumNetworkEvents(m_pSocket->m_fd, m_sync_event, &events);
591                        if (res) {
592                                res = ConvertMSWErrorCode(WSAGetLastError());
593                                return false;
594                        }
595
596                        if (m_waiting & WAIT_CONNECT) {
597                                if (events.lNetworkEvents & FD_CONNECT) {
598                                        m_triggered |= WAIT_CONNECT;
599                                        m_triggered_errors[0] = ConvertMSWErrorCode(events.iErrorCode[FD_CONNECT_BIT]);
600                                        m_waiting &= ~WAIT_CONNECT;
601                                }
602                        }
603                        if (m_waiting & WAIT_READ) {
604                                if (events.lNetworkEvents & FD_READ) {
605                                        m_triggered |= WAIT_READ;
606                                        m_triggered_errors[1] = ConvertMSWErrorCode(events.iErrorCode[FD_READ_BIT]);
607                                        m_waiting &= ~WAIT_READ;
608                                }
609                        }
610                        if (m_waiting & WAIT_WRITE) {
611                                if (events.lNetworkEvents & FD_WRITE) {
612                                        m_triggered |= WAIT_WRITE;
613                                        m_triggered_errors[2] = ConvertMSWErrorCode(events.iErrorCode[FD_WRITE_BIT]);
614                                        m_waiting &= ~WAIT_WRITE;
615                                }
616                        }
617                        if (m_waiting & WAIT_ACCEPT) {
618                                if (events.lNetworkEvents & FD_ACCEPT) {
619                                        m_triggered |= WAIT_ACCEPT;
620                                        m_triggered_errors[3] = ConvertMSWErrorCode(events.iErrorCode[FD_ACCEPT_BIT]);
621                                        m_waiting &= ~WAIT_ACCEPT;
622                                }
623                        }
624                        if (m_waiting & WAIT_CLOSE) {
625                                if (events.lNetworkEvents & FD_CLOSE) {
626                                        m_triggered |= WAIT_CLOSE;
627                                        m_triggered_errors[4] = ConvertMSWErrorCode(events.iErrorCode[FD_CLOSE_BIT]);
628                                        m_waiting &= ~WAIT_CLOSE;
629                                }
630                        }
631
632                        if (m_triggered || !m_waiting)
633                                return true;
634#else
635                        fd_set readfds;
636                        fd_set writefds;
637                        FD_ZERO(&readfds);
638                        FD_ZERO(&writefds);
639
640                        FD_SET(m_pipe[0], &readfds);
641                        if (!(m_waiting & WAIT_CONNECT))
642                                FD_SET(m_pSocket->m_fd, &readfds);
643
644                        if (m_waiting & (WAIT_WRITE | WAIT_CONNECT))
645                                FD_SET(m_pSocket->m_fd, &writefds);
646
647                        int max = wxMax(m_pipe[0], m_pSocket->m_fd) + 1;
648
649                        l.unlock();
650
651                        int res = select(max, &readfds, &writefds, 0, 0);
652
653                        l.lock();
654
655                        if (res > 0 && FD_ISSET(m_pipe[0], &readfds)) {
656                                char buffer[100];
657                                int damn_spurious_warning = read(m_pipe[0], buffer, 100);
658                                (void)damn_spurious_warning; // We do not care about return value and this is definitely correct!
659                        }
660
661                        if (m_quit || !m_pSocket || m_pSocket->m_fd == -1) {
662                                return false;
663                        }
664
665                        if (!res)
666                                continue;
667                        if (res == -1) {
668                                res = errno;
669                                //printf("select failed: %s\n", (const char *)CSocket::GetErrorDescription(res).mb_str());
670                                //fflush(stdout);
671
672                                if (res == EINTR)
673                                        continue;
674
675                                return false;
676                        }
677
678                        if (m_waiting & WAIT_CONNECT) {
679                                if (FD_ISSET(m_pSocket->m_fd, &writefds)) {
680                                        int error;
681                                        socklen_t len = sizeof(error);
682                                        int res = getsockopt(m_pSocket->m_fd, SOL_SOCKET, SO_ERROR, &error, &len);
683                                        if (res)
684                                                error = errno;
685                                        m_triggered |= WAIT_CONNECT;
686                                        m_triggered_errors[0] = error;
687                                        m_waiting &= ~WAIT_CONNECT;
688                                }
689                        }
690                        else if (m_waiting & WAIT_ACCEPT) {
691                                if (FD_ISSET(m_pSocket->m_fd, &readfds)) {
692                                        m_triggered |= WAIT_ACCEPT;
693                                        m_waiting &= ~WAIT_ACCEPT;
694                                }
695                        }
696                        else if (m_waiting & WAIT_READ) {
697                                if (FD_ISSET(m_pSocket->m_fd, &readfds)) {
698                                        m_triggered |= WAIT_READ;
699                                        m_waiting &= ~WAIT_READ;
700                                }
701                        }
702                        if (m_waiting & WAIT_WRITE) {
703                                if (FD_ISSET(m_pSocket->m_fd, &writefds)) {
704                                        m_triggered |= WAIT_WRITE;
705                                        m_waiting &= ~WAIT_WRITE;
706                                }
707                        }
708
709                        if (m_triggered || !m_waiting)
710                                return true;
711#endif
712                }
713        }
714
715        void SendEvents()
716        {
717                if (!m_pSocket || !m_pSocket->m_pEvtHandler)
718                        return;
719                if (m_triggered & WAIT_READ) {
720                        if (m_pSocket->m_synchronous_read_cb)
721                                m_pSocket->m_synchronous_read_cb->cb();
722                        m_pSocket->m_pEvtHandler->SendEvent<CSocketEvent>(m_pSocket, SocketEventType::read, m_triggered_errors[1]);
723                        m_triggered &= ~WAIT_READ;
724                }
725                if (m_triggered & WAIT_WRITE) {
726                        m_pSocket->m_pEvtHandler->SendEvent<CSocketEvent>(m_pSocket, SocketEventType::write, m_triggered_errors[2]);
727                        m_triggered &= ~WAIT_WRITE;
728                }
729                if (m_triggered & WAIT_ACCEPT) {
730                        m_pSocket->m_pEvtHandler->SendEvent<CSocketEvent>(m_pSocket, SocketEventType::connection, m_triggered_errors[3]);
731                        m_triggered &= ~WAIT_ACCEPT;
732                }
733                if (m_triggered & WAIT_CLOSE) {
734                        SendCloseEvent();
735                }
736        }
737
738        void SendCloseEvent()
739        {
740                if( !m_pSocket || !m_pSocket->m_pEvtHandler ) {
741                        return;
742                }
743
744#ifdef __WXMSW__
745                // MSDN says this:
746                //   FD_CLOSE being posted after all data is read from a socket.
747                //   An application should check for remaining data upon receipt
748                //   of FD_CLOSE to avoid any possibility of losing data.
749                // First half is actually plain wrong.
750                char buf;
751                if( !m_triggered_errors[4] && recv( m_pSocket->m_fd, &buf, 1, MSG_PEEK ) > 0) {
752                        if( !(m_waiting & WAIT_READ) ) {
753                                return;
754                        }
755                        m_pSocket->m_pEvtHandler->SendEvent<CSocketEvent>(m_pSocket, SocketEventType::read, 0);
756                }
757                else
758#endif
759                {
760                        m_pSocket->m_pEvtHandler->SendEvent<CSocketEvent>(m_pSocket, SocketEventType::close, m_triggered_errors[4]);
761                        m_triggered &= ~WAIT_CLOSE;
762                }
763        }
764
765        // Call only while locked
766        bool IdleLoop(scoped_lock & l)
767        {
768                if (m_quit)
769                        return false;
770                while (!m_pSocket || (!m_waiting && m_host.empty())) {
771                        m_threadwait = true;
772                        m_condition.wait(l);
773
774                        if (m_quit)
775                                return false;
776                }
777
778                return true;
779        }
780
781        virtual ExitCode Entry()
782        {
783                scoped_lock l(m_sync);
784                for (;;) {
785                        if (!IdleLoop(l)) {
786                                m_finished = true;
787                                return 0;
788                        }
789
790                        if (m_pSocket->m_state == CSocket::listening) {
791                                while (IdleLoop(l)) {
792                                        if (m_pSocket->m_fd == -1) {
793                                                m_waiting = 0;
794                                                break;
795                                        }
796                                        if (!DoWait(0, l))
797                                                break;
798                                        SendEvents();
799                                }
800                        }
801                        else {
802                                if (m_pSocket->m_state == CSocket::connecting) {
803                                        if (!DoConnect(l))
804                                                continue;
805                                }
806
807#ifdef __WXMSW__
808                                m_waiting |= WAIT_CLOSE;
809                                int wait_close = WAIT_CLOSE;
810#endif
811                                while (IdleLoop(l)) {
812                                        if (m_pSocket->m_fd == -1) {
813                                                m_waiting = 0;
814                                                break;
815                                        }
816                                        bool res = DoWait(0, l);
817
818                                        if (m_triggered & WAIT_CLOSE && m_pSocket) {
819                                                m_pSocket->m_state = CSocket::closing;
820#ifdef __WXMSW__
821                                                wait_close = 0;
822#endif
823                                        }
824
825                                        if (!res)
826                                                break;
827
828                                        SendEvents();
829#ifdef __WXMSW__
830                                        m_waiting |= wait_close;
831#endif
832                                }
833                        }
834                }
835
836                m_finished = true;
837                return 0;
838        }
839
840        CSocket* m_pSocket{};
841
842        std::string m_host;
843        std::string m_port;
844        std::string m_bind;
845
846#ifdef __WXMSW__
847        // We wait on this using WSAWaitForMultipleEvents
848        WSAEVENT m_sync_event;
849#else
850        // A pipe is used to unblock select
851        int m_pipe[2];
852#endif
853
854        mutex m_sync;
855        condition m_condition;
856
857        bool m_started{};
858        bool m_quit{};
859        bool m_finished{};
860
861        // The socket events we are waiting for
862        int m_waiting{};
863
864        // The triggered socket events
865        int m_triggered{};
866        int m_triggered_errors[WAIT_EVENTCOUNT];
867
868        // Thread waits for instructions
869        bool m_threadwait{};
870};
871
872CSocket::CSocket(CEventHandler* pEvtHandler)
873        : m_pEvtHandler(pEvtHandler)
874{
875#ifdef ERRORCODETEST
876        CErrorCodeTest test;
877#endif
878        m_fd = -1;
879        m_state = none;
880        m_pSocketThread = 0;
881        m_flags = 0;
882
883        m_port = 0;
884        m_family = AF_UNSPEC;
885
886        m_buffer_sizes[0] = -1;
887        m_buffer_sizes[1] = -1;
888}
889
890CSocket::~CSocket()
891{
892        if (m_state != none)
893                Close();
894
895        DetachThread();
896}
897
898void CSocket::DetachThread()
899{
900        if (!m_pSocketThread)
901                return;
902
903        scoped_lock l(m_pSocketThread->m_sync);
904        m_pSocketThread->SetSocket(0, l);
905        if (m_pSocketThread->m_finished) {
906                m_pSocketThread->WakeupThread(l);
907                l.unlock();
908                m_pSocketThread->Wait();
909                delete m_pSocketThread;
910        }
911        else {
912                if (!m_pSocketThread->m_started) {
913                        l.unlock();
914                        delete m_pSocketThread;
915                }
916                else {
917                        m_pSocketThread->m_quit = true;
918                        m_pSocketThread->WakeupThread(l);
919                        l.unlock();
920
921                        scoped_lock wl(waiting_socket_threads_mutex);
922                        waiting_socket_threads.push_back(m_pSocketThread);
923                }
924        }
925        m_pSocketThread = 0;
926
927        Cleanup(false);
928}
929
930int CSocket::Connect(wxString const& host, unsigned int port, address_family family, wxString const& bind)
931{
932        if (m_state != none)
933                return EISCONN;
934
935        if (port < 1 || port > 65535)
936                return EINVAL;
937
938        switch (family)
939        {
940        case unspec:
941                m_family = AF_UNSPEC;
942                break;
943        case ipv4:
944                m_family = AF_INET;
945                break;
946        case ipv6:
947                m_family = AF_INET6;
948                break;
949        default:
950                return EINVAL;
951        }
952
953        if (m_pSocketThread && m_pSocketThread->m_started) {
954                scoped_lock l(m_pSocketThread->m_sync);
955                if (!m_pSocketThread->m_threadwait) {
956                        m_pSocketThread->WakeupThread(l);
957                        l.unlock();
958                        // Wait a small amount of time
959                        wxMilliSleep(100);
960
961                        l.lock();
962                        if (!m_pSocketThread->m_threadwait) {
963                                // Inside a blocking call, e.g. getaddrinfo
964                                l.unlock();
965                                DetachThread();
966                        }
967                }
968        }
969        if (!m_pSocketThread) {
970                m_pSocketThread = new CSocketThread();
971                m_pSocketThread->SetSocket(this);
972        }
973
974        m_state = connecting;
975
976        m_host = host;
977        m_port = port;
978        int res = m_pSocketThread->Connect(bind);
979        if (res) {
980                m_state = none;
981                delete m_pSocketThread;
982                m_pSocketThread = 0;
983                return res;
984        }
985
986        return EINPROGRESS;
987}
988
989void CSocket::SetEventHandler(CEventHandler* pEvtHandler)
990{
991        if (m_pSocketThread) {
992                scoped_lock l(m_pSocketThread->m_sync);
993
994                if (m_pEvtHandler == pEvtHandler) {
995                        return;
996                }
997
998                ChangeSocketEventHandler(m_pEvtHandler, pEvtHandler, this);
999
1000                m_pEvtHandler = pEvtHandler;
1001
1002                if (pEvtHandler && m_state == connected) {
1003#ifdef __WXMSW__
1004                        // If a graceful shutdown is going on in background already,
1005                        // no further events are recorded. Send out events we're not
1006                        // waiting for (i.e. they got triggered already) manually.
1007
1008                        if (!(m_pSocketThread->m_waiting & WAIT_WRITE)) {
1009                                pEvtHandler->SendEvent<CSocketEvent>(this, SocketEventType::write, 0);
1010                        }
1011
1012                        pEvtHandler->SendEvent<CSocketEvent>(this, SocketEventType::read, 0);
1013                        if (m_pSocketThread->m_waiting & WAIT_READ) {
1014                                m_pSocketThread->m_waiting &= ~WAIT_READ;
1015                                m_pSocketThread->WakeupThread(l);
1016                        }
1017#else
1018                        m_pSocketThread->m_waiting |= WAIT_READ | WAIT_WRITE;
1019                        m_pSocketThread->WakeupThread(l);
1020#endif
1021                }
1022                else if (pEvtHandler && m_state == closing) {
1023                        if (!(m_pSocketThread->m_triggered & WAIT_READ)) {
1024                                m_pSocketThread->m_waiting |= WAIT_READ;
1025                        }
1026                        m_pSocketThread->SendEvents();
1027                }
1028        }
1029        else {
1030                ChangeSocketEventHandler(m_pEvtHandler, pEvtHandler, this);
1031                m_pEvtHandler = pEvtHandler;
1032        }
1033}
1034
1035#define ERRORDECL(c, desc) { c, _T(#c), desc },
1036
1037struct Error_table
1038{
1039        int code;
1040        const wxChar* const name;
1041        const wxChar* const description;
1042};
1043
1044static Error_table const error_table[] =
1045{
1046        ERRORDECL(EACCES, TRANSLATE_T("Permission denied"))
1047        ERRORDECL(EADDRINUSE, TRANSLATE_T("Local address in use"))
1048        ERRORDECL(EAFNOSUPPORT, TRANSLATE_T("The specified address family is not supported"))
1049        ERRORDECL(EINPROGRESS, TRANSLATE_T("Operation in progress"))
1050        ERRORDECL(EINVAL, TRANSLATE_T("Invalid argument passed"))
1051        ERRORDECL(EMFILE, TRANSLATE_T("Process file table overflow"))
1052        ERRORDECL(ENFILE, TRANSLATE_T("System limit of open files exceeded"))
1053        ERRORDECL(ENOBUFS, TRANSLATE_T("Out of memory"))
1054        ERRORDECL(ENOMEM, TRANSLATE_T("Out of memory"))
1055        ERRORDECL(EPERM, TRANSLATE_T("Permission denied"))
1056        ERRORDECL(EPROTONOSUPPORT, TRANSLATE_T("Protocol not supported"))
1057        ERRORDECL(EAGAIN, TRANSLATE_T("Resource temporarily unavailable"))
1058        ERRORDECL(EALREADY, TRANSLATE_T("Operation already in progress"))
1059        ERRORDECL(EBADF, TRANSLATE_T("Bad file descriptor"))
1060        ERRORDECL(ECONNREFUSED, TRANSLATE_T("Connection refused by server"))
1061        ERRORDECL(EFAULT, TRANSLATE_T("Socket address outside address space"))
1062        ERRORDECL(EINTR, TRANSLATE_T("Interrupted by signal"))
1063        ERRORDECL(EISCONN, TRANSLATE_T("Socket already connected"))
1064        ERRORDECL(ENETUNREACH, TRANSLATE_T("Network unreachable"))
1065        ERRORDECL(ENOTSOCK, TRANSLATE_T("File descriptor not a socket"))
1066        ERRORDECL(ETIMEDOUT, TRANSLATE_T("Connection attempt timed out"))
1067        ERRORDECL(EHOSTUNREACH, TRANSLATE_T("No route to host"))
1068        ERRORDECL(ENOTCONN, TRANSLATE_T("Socket not connected"))
1069        ERRORDECL(ENETRESET, TRANSLATE_T("Connection reset by network"))
1070        ERRORDECL(EOPNOTSUPP, TRANSLATE_T("Operation not supported"))
1071        ERRORDECL(ESHUTDOWN, TRANSLATE_T("Socket has been shut down"))
1072        ERRORDECL(EMSGSIZE, TRANSLATE_T("Message too large"))
1073        ERRORDECL(ECONNABORTED, TRANSLATE_T("Connection aborted"))
1074        ERRORDECL(ECONNRESET, TRANSLATE_T("Connection reset by peer"))
1075        ERRORDECL(EPIPE, TRANSLATE_T("Local endpoint has been closed"))
1076        ERRORDECL(EHOSTDOWN, TRANSLATE_T("Host is down"))
1077
1078        // Getaddrinfo related
1079#ifdef EAI_ADDRFAMILY
1080        ERRORDECL(EAI_ADDRFAMILY, TRANSLATE_T("Network host does not have any network addresses in the requested address family"))
1081#endif
1082        ERRORDECL(EAI_AGAIN, TRANSLATE_T("Temporary failure in name resolution"))
1083        ERRORDECL(EAI_BADFLAGS, TRANSLATE_T("Invalid value for ai_flags"))
1084#ifdef EAI_BADHINTS
1085        ERRORDECL(EAI_BADHINTS, TRANSLATE_T("Invalid value for hints"))
1086#endif
1087        ERRORDECL(EAI_FAIL, TRANSLATE_T("Nonrecoverable failure in name resolution"))
1088        ERRORDECL(EAI_FAMILY, TRANSLATE_T("The ai_family member is not supported"))
1089        ERRORDECL(EAI_MEMORY, TRANSLATE_T("Memory allocation failure"))
1090#ifdef EAI_NODATA
1091        ERRORDECL(EAI_NODATA, TRANSLATE_T("No address associated with nodename"))
1092#endif
1093        ERRORDECL(EAI_NONAME, TRANSLATE_T("Neither nodename nor servname provided, or not known"))
1094#ifdef EAI_OVERFLOW
1095        ERRORDECL(EAI_OVERFLOW, TRANSLATE_T("Argument buffer overflow"))
1096#endif
1097#ifdef EAI_PROTOCOL
1098        ERRORDECL(EAI_PROTOCOL, TRANSLATE_T("Resolved protocol is unknown"))
1099#endif
1100        ERRORDECL(EAI_SERVICE, TRANSLATE_T("The servname parameter is not supported for ai_socktype"))
1101        ERRORDECL(EAI_SOCKTYPE, TRANSLATE_T("The ai_socktype member is not supported"))
1102#ifdef EAI_SYSTEM
1103        ERRORDECL(EAI_SYSTEM, TRANSLATE_T("Other system error"))
1104#endif
1105
1106        // Codes that have no POSIX equivalence
1107#ifdef __WXMSW__
1108        ERRORDECL(WSANOTINITIALISED, TRANSLATE_T("Not initialized, need to call WSAStartup"))
1109        ERRORDECL(WSAENETDOWN, TRANSLATE_T("System's network subsystem has failed"))
1110        ERRORDECL(WSAEPROTOTYPE, TRANSLATE_T("Protocol not supported on given socket type"))
1111        ERRORDECL(WSAESOCKTNOSUPPORT, TRANSLATE_T("Socket type not supported for address family"))
1112        ERRORDECL(WSAEADDRNOTAVAIL, TRANSLATE_T("Cannot assign requested address"))
1113        ERRORDECL(ERROR_NETNAME_DELETED, TRANSLATE_T("The specified network name is no longer available"))
1114#endif
1115        { 0, 0, 0 }
1116};
1117
1118wxString CSocket::GetErrorString(int error)
1119{
1120        for (int i = 0; error_table[i].code; ++i)
1121        {
1122                if (error != error_table[i].code)
1123                        continue;
1124
1125                return error_table[i].name;
1126        }
1127
1128        return wxString::Format(_T("%d"), error);
1129}
1130
1131wxString CSocket::GetErrorDescription(int error)
1132{
1133        for (int i = 0; error_table[i].code; ++i)
1134        {
1135                if (error != error_table[i].code)
1136                        continue;
1137
1138                return wxString(error_table[i].name) + _T(" - ") + wxGetTranslation(error_table[i].description);
1139        }
1140
1141        return wxString::Format(_T("%d"), error);
1142}
1143
1144int CSocket::Close()
1145{
1146        if (m_pSocketThread) {
1147                scoped_lock l(m_pSocketThread->m_sync);
1148                int fd = m_fd;
1149                m_fd = -1;
1150
1151                m_pSocketThread->m_host.clear();
1152                m_pSocketThread->m_port.clear();
1153
1154                        m_pSocketThread->WakeupThread(l);
1155
1156                CSocketThread::CloseSocketFd(fd);
1157                m_state = none;
1158
1159                m_pSocketThread->m_triggered = 0;
1160                for (int i = 0; i < WAIT_EVENTCOUNT; ++i) {
1161                        m_pSocketThread->m_triggered_errors[i] = 0;
1162                }
1163
1164                if (m_pEvtHandler) {
1165                        RemoveSocketEvents(m_pEvtHandler, this);
1166                        m_pEvtHandler = 0;
1167                }
1168        }
1169        else {
1170                int fd = m_fd;
1171                m_fd = -1;
1172                CSocketThread::CloseSocketFd(fd);
1173                m_state = none;
1174
1175                if (m_pEvtHandler) {
1176                        RemoveSocketEvents(m_pEvtHandler, this);
1177                        m_pEvtHandler = 0;
1178                }
1179        }
1180
1181        return 0;
1182}
1183
1184CSocket::SocketState CSocket::GetState()
1185{
1186        SocketState state;
1187        if (m_pSocketThread)
1188                m_pSocketThread->m_sync.lock();
1189        state = m_state;
1190        if (m_pSocketThread)
1191                m_pSocketThread->m_sync.unlock();
1192
1193        return state;
1194}
1195
1196void CSocket::Cleanup(bool force)
1197{
1198        scoped_lock wl(waiting_socket_threads_mutex);
1199        auto iter = waiting_socket_threads.begin();
1200        for (; iter != waiting_socket_threads.end(); ++iter) {
1201                CSocketThread *const pThread = *iter;
1202
1203                if (!force) {
1204                        scoped_lock l(pThread->m_sync);
1205                        if (!pThread->m_finished) {
1206                                break;
1207                        }
1208                }
1209
1210                pThread->Wait(wxTHREAD_WAIT_BLOCK);
1211                delete pThread;
1212        }
1213        waiting_socket_threads.erase(waiting_socket_threads.begin(), iter);
1214}
1215
1216int CSocket::Read(void* buffer, unsigned int size, int& error)
1217{
1218        int res = recv(m_fd, (char*)buffer, size, 0);
1219
1220        if (res == -1) {
1221                error = GetLastSocketError();
1222                if (error == EAGAIN) {
1223                        if (m_pSocketThread) {
1224                                scoped_lock l(m_pSocketThread->m_sync);
1225                                if (!(m_pSocketThread->m_waiting & WAIT_READ)) {
1226                                        m_pSocketThread->m_waiting |= WAIT_READ;
1227                                        m_pSocketThread->WakeupThread(l);
1228                                }
1229                        }
1230                }
1231        }
1232        else
1233                error = 0;
1234
1235        return res;
1236}
1237
1238int CSocket::Peek(void* buffer, unsigned int size, int& error)
1239{
1240        int res = recv(m_fd, (char*)buffer, size, MSG_PEEK);
1241
1242        if (res == -1) {
1243                error = GetLastSocketError();
1244        }
1245        else
1246                error = 0;
1247
1248        return res;
1249}
1250
1251int CSocket::Write(const void* buffer, unsigned int size, int& error)
1252{
1253#ifdef MSG_NOSIGNAL
1254        const int flags = MSG_NOSIGNAL;
1255#else
1256        const int flags = 0;
1257
1258#if !defined(SO_NOSIGPIPE) && !defined(__WXMSW__)
1259        // Some systems have neither. Need to block signal
1260        struct sigaction old_action;
1261        struct sigaction action = {0};
1262        action.sa_handler = SIG_IGN;
1263        int signal_set = sigaction(SIGPIPE, &action, &old_action);
1264#endif
1265
1266#endif
1267
1268        int res = send(m_fd, (const char*)buffer, size, flags);
1269
1270#if !defined(MSG_NOSIGNAL) && !defined(SO_NOSIGPIPE) && !defined(__WXMSW__)
1271        // Restore previous signal handler
1272        if (!signal_set)
1273                sigaction(SIGPIPE, &old_action, 0);
1274#endif
1275
1276        if (res == -1) {
1277                error = GetLastSocketError();
1278                if (error == EAGAIN) {
1279                        if (m_pSocketThread) {
1280                                scoped_lock l (m_pSocketThread->m_sync);
1281                                if (!(m_pSocketThread->m_waiting & WAIT_WRITE)) {
1282                                        m_pSocketThread->m_waiting |= WAIT_WRITE;
1283                                        m_pSocketThread->WakeupThread(l);
1284                                }
1285                        }
1286                }
1287        }
1288        else
1289                error = 0;
1290
1291        return res;
1292}
1293
1294wxString CSocket::AddressToString(const struct sockaddr* addr, int addr_len, bool with_port /*=true*/, bool strip_zone_index/*=false*/)
1295{
1296        char hostbuf[NI_MAXHOST];
1297        char portbuf[NI_MAXSERV];
1298
1299        int res = getnameinfo(addr, addr_len, hostbuf, NI_MAXHOST, portbuf, NI_MAXSERV, NI_NUMERICHOST | NI_NUMERICSERV);
1300        if (res) // Should never fail
1301                return wxString();
1302
1303        wxString host = wxString(hostbuf, wxConvLibc);
1304        wxString port = wxString(portbuf, wxConvLibc);
1305
1306        // IPv6 uses colons as separator, need to enclose address
1307        // to avoid ambiguity if also showing port
1308        if (addr->sa_family == AF_INET6) {
1309                if (strip_zone_index) {
1310                        int pos = host.Find('%');
1311                        if (pos != -1)
1312                                host.Truncate(pos);
1313                }
1314                if (with_port)
1315                        host = _T("[") + host + _T("]");
1316        }
1317
1318        if (with_port)
1319                return host + _T(":") + port;
1320        else
1321                return host;
1322}
1323
1324wxString CSocket::AddressToString(char const* buf, int buf_len)
1325{
1326        if (buf_len != 4 && buf_len != 16) {
1327                return wxString();
1328        }
1329
1330        sockaddr_u addr;
1331        if (buf_len == 16) {
1332                memcpy(&addr.in6.sin6_addr, buf, buf_len);
1333                addr.in6.sin6_family = AF_INET6;
1334        }
1335        else {
1336                memcpy(&addr.in4.sin_addr, buf, buf_len);
1337                addr.in4.sin_family = AF_INET;
1338        }
1339
1340
1341        return AddressToString(&addr.sockaddr, sizeof(addr), false, true);
1342}
1343
1344wxString CSocket::GetLocalIP(bool strip_zone_index /*=false*/) const
1345{
1346        struct sockaddr_storage addr;
1347        socklen_t addr_len = sizeof(addr);
1348        int res = getsockname(m_fd, (sockaddr*)&addr, &addr_len);
1349        if (res)
1350                return wxString();
1351
1352        return AddressToString((sockaddr *)&addr, addr_len, false, strip_zone_index);
1353}
1354
1355wxString CSocket::GetPeerIP(bool strip_zone_index /*=false*/) const
1356{
1357        struct sockaddr_storage addr;
1358        socklen_t addr_len = sizeof(addr);
1359        int res = getpeername(m_fd, (sockaddr*)&addr, &addr_len);
1360        if (res)
1361                return wxString();
1362
1363        return AddressToString((sockaddr *)&addr, addr_len, false, strip_zone_index);
1364}
1365
1366CSocket::address_family CSocket::GetAddressFamily() const
1367{
1368        sockaddr_u addr;
1369        socklen_t addr_len = sizeof(addr);
1370        int res = getsockname(m_fd, &addr.sockaddr, &addr_len);
1371        if (res)
1372                return unspec;
1373
1374        switch (addr.sockaddr.sa_family)
1375        {
1376        case AF_INET:
1377                return ipv4;
1378        case AF_INET6:
1379                return ipv6;
1380        default:
1381                return unspec;
1382        }
1383}
1384
1385int CSocket::Listen(address_family family, int port)
1386{
1387        if (m_state != none)
1388                return EALREADY;
1389
1390        if (port < 0 || port > 65535)
1391                return EINVAL;
1392
1393        switch (family)
1394        {
1395        case unspec:
1396                m_family = AF_UNSPEC;
1397                break;
1398        case ipv4:
1399                m_family = AF_INET;
1400                break;
1401        case ipv6:
1402                m_family = AF_INET6;
1403                break;
1404        default:
1405                return EINVAL;
1406        }
1407
1408        {
1409                struct addrinfo hints = {0};
1410                hints.ai_family = m_family;
1411                hints.ai_socktype = SOCK_STREAM;
1412                hints.ai_flags = AI_PASSIVE;
1413#ifdef AI_NUMERICSERV
1414                // Some systems like Windows or OS X don't know AI_NUMERICSERV.
1415                hints.ai_flags |= AI_NUMERICSERV;
1416#endif
1417
1418                char portstring[6];
1419                sprintf(portstring, "%d", port);
1420
1421                struct addrinfo* addressList = 0;
1422                int res = getaddrinfo(0, portstring, &hints, &addressList);
1423
1424                if (res) {
1425#ifdef __WXMSW__
1426                        return ConvertMSWErrorCode(res);
1427#else
1428                        return res;
1429#endif
1430                }
1431
1432                for (struct addrinfo* addr = addressList; addr; addr = addr->ai_next) {
1433                        m_fd = CSocketThread::CreateSocketFd(*addr);
1434                        res = GetLastSocketError();
1435
1436                        if (m_fd == -1)
1437                                continue;
1438
1439                        res = bind(m_fd, addr->ai_addr, addr->ai_addrlen);
1440                        if (!res)
1441                                break;
1442
1443                        res = GetLastSocketError();
1444                        CSocketThread::CloseSocketFd(m_fd);
1445                }
1446                freeaddrinfo(addressList);
1447                if (m_fd == -1)
1448                        return res;
1449        }
1450
1451        int res = listen(m_fd, 1);
1452        if (res) {
1453                res = GetLastSocketError();
1454                CSocketThread::CloseSocketFd(m_fd);
1455                m_fd = -1;
1456                return res;
1457        }
1458
1459        m_state = listening;
1460
1461        m_pSocketThread = new CSocketThread();
1462        m_pSocketThread->SetSocket(this);
1463
1464        m_pSocketThread->m_waiting = WAIT_ACCEPT;
1465
1466        m_pSocketThread->Start();
1467
1468        return 0;
1469}
1470
1471int CSocket::GetLocalPort(int& error)
1472{
1473        sockaddr_u addr;
1474        socklen_t addr_len = sizeof(addr);
1475        error = getsockname(m_fd, &addr.sockaddr, &addr_len);
1476        if (error) {
1477#ifdef __WXMSW__
1478                error = ConvertMSWErrorCode(error);
1479#endif
1480                return -1;
1481        }
1482
1483        if (addr.storage.ss_family == AF_INET)
1484                return ntohs(addr.in4.sin_port);
1485        else if (addr.storage.ss_family == AF_INET6)
1486                return ntohs(addr.in6.sin6_port);
1487
1488        error = EINVAL;
1489        return -1;
1490}
1491
1492int CSocket::GetRemotePort(int& error)
1493{
1494        sockaddr_u addr;
1495        socklen_t addr_len = sizeof(addr);
1496        error = getpeername(m_fd, &addr.sockaddr, &addr_len);
1497        if (error)
1498        {
1499#ifdef __WXMSW__
1500                error = ConvertMSWErrorCode(error);
1501#endif
1502                return -1;
1503        }
1504
1505        if (addr.storage.ss_family == AF_INET)
1506                return ntohs(addr.in4.sin_port);
1507        else if (addr.storage.ss_family == AF_INET6)
1508                return ntohs(addr.in6.sin6_port);
1509
1510        error = EINVAL;
1511        return -1;
1512}
1513
1514CSocket* CSocket::Accept(int &error)
1515{
1516        if (m_pSocketThread) {
1517                scoped_lock l(m_pSocketThread->m_sync);
1518                m_pSocketThread->m_waiting |= WAIT_ACCEPT;
1519                m_pSocketThread->WakeupThread(l);
1520        }
1521        int fd = accept(m_fd, 0, 0);
1522        if (fd == -1) {
1523                error = GetLastSocketError();
1524                return 0;
1525        }
1526
1527#if defined(SO_NOSIGPIPE) && !defined(MSG_NOSIGNAL)
1528        // We do not want SIGPIPE if writing to socket.
1529        const int value = 1;
1530        setsockopt(fd, SOL_SOCKET, SO_NOSIGPIPE, &value, sizeof(int));
1531#endif
1532
1533        SetNonblocking(fd);
1534
1535        DoSetBufferSizes(fd, m_buffer_sizes[0], m_buffer_sizes[1]);
1536
1537        CSocket* pSocket = new CSocket(0);
1538        pSocket->m_state = connected;
1539        pSocket->m_fd = fd;
1540        pSocket->m_pSocketThread = new CSocketThread();
1541        pSocket->m_pSocketThread->SetSocket(pSocket);
1542        pSocket->m_pSocketThread->m_waiting = WAIT_READ | WAIT_WRITE;
1543        pSocket->m_pSocketThread->Start();
1544
1545        return pSocket;
1546}
1547
1548int CSocket::SetNonblocking(int fd)
1549{
1550        // Set socket to non-blocking.
1551#ifdef __WXMSW__
1552        unsigned long nonblock = 1;
1553        int res = ioctlsocket(fd, FIONBIO, &nonblock);
1554        if (!res)
1555                return 0;
1556        else
1557                return ConvertMSWErrorCode(WSAGetLastError());
1558#else
1559        int flags = fcntl(fd, F_GETFL);
1560        if (flags == -1)
1561                return errno;
1562        int res = fcntl(fd, F_SETFL, flags | O_NONBLOCK);
1563        if (res == -1)
1564                return errno;
1565        return 0;
1566#endif
1567}
1568
1569void CSocket::SetFlags(int flags)
1570{
1571        if (m_pSocketThread)
1572                m_pSocketThread->m_sync.lock();
1573
1574        if (m_fd != -1)
1575                DoSetFlags(m_fd, flags, flags ^ m_flags);
1576        m_flags = flags;
1577
1578        if (m_pSocketThread)
1579                m_pSocketThread->m_sync.unlock();
1580}
1581
1582int CSocket::DoSetFlags(int fd, int flags, int flags_mask)
1583{
1584        if (flags_mask & flag_nodelay) {
1585                const int value = (flags & flag_nodelay) ? 1 : 0;
1586                int res = setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, (const char*)&value, sizeof(value));
1587                if (res != 0) {
1588                        return GetLastSocketError();
1589                }
1590        }
1591        if (flags_mask & flag_keepalive) {
1592                const int value = (flags & flag_keepalive) ? 1 : 0;
1593                int res = setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, (const char*)&value, sizeof(value));
1594                if (res != 0) {
1595                        return GetLastSocketError();
1596                }
1597        }
1598
1599        return 0;
1600}
1601
1602int CSocket::SetBufferSizes(int size_read, int size_write)
1603{
1604        int ret = 0;
1605
1606        if (m_pSocketThread)
1607                m_pSocketThread->m_sync.lock();
1608
1609        m_buffer_sizes[0] = size_read;
1610        m_buffer_sizes[1] = size_write;
1611
1612        if (m_fd != -1)
1613                ret = DoSetBufferSizes(m_fd, size_read, size_write);
1614
1615        if (m_pSocketThread)
1616                m_pSocketThread->m_sync.unlock();
1617
1618        return ret;
1619}
1620
1621int CSocket::DoSetBufferSizes(int fd, int size_read, int size_write)
1622{
1623        int ret = 0;
1624
1625        if (size_read != -1) {
1626                int res = setsockopt(fd, SOL_SOCKET, SO_RCVBUF, (const char*)&size_read, sizeof(size_read));
1627                if (res != 0) {
1628                        ret = GetLastSocketError();
1629                }
1630        }
1631
1632        if (size_write != -1) {
1633                int res = setsockopt(fd, SOL_SOCKET, SO_SNDBUF, (const char*)&size_write, sizeof(size_write));
1634                if (res != 0) {
1635                        ret = GetLastSocketError();
1636                }
1637        }
1638
1639        return ret;
1640}
1641
1642void CSocket::SetSynchronousReadCallback(CCallback* cb)
1643{
1644        if (m_pSocketThread)
1645                m_pSocketThread->m_sync.lock();
1646
1647        m_synchronous_read_cb = cb;
1648
1649        if (m_pSocketThread)
1650                m_pSocketThread->m_sync.unlock();
1651}
1652
1653wxString CSocket::GetPeerHost() const
1654{
1655        return m_host;
1656}
Note: See TracBrowser for help on using the repository browser.