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

Last change on this file since 3185 was 3185, checked in by jrpelegrina, 2 years ago

Update new version: 3.15.02

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