~ubuntu-branches/ubuntu/lucid/znc/lucid-backports

« back to all changes in this revision

Viewing changes to Socket.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Scott Kitterman
  • Date: 2011-05-11 13:34:53 UTC
  • mfrom: (13.1.8 sid)
  • Revision ID: james.westby@ubuntu.com-20110511133453-334862gk6gh8dmwp
Tags: 0.092-3~lucid1
Automated backport upload; no source changes.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
1
/*
2
 
 * Copyright (C) 2004-2009  See the AUTHORS file for details.
 
2
 * Copyright (C) 2004-2010  See the AUTHORS file for details.
3
3
 *
4
4
 * This program is free software; you can redistribute it and/or modify it
5
5
 * under the terms of the GNU General Public License version 2 as published
7
7
 */
8
8
 
9
9
#include "Socket.h"
10
 
#ifdef HAVE_ARES
11
 
#include <ares.h>
12
 
#endif
13
 
 
14
 
#ifdef HAVE_ARES
15
 
struct DNSLookup {
16
 
        bool bSocketDead;
17
 
        bool bLookupDone;
18
 
        // When both of the above are true, this struct can be freed
19
 
 
20
 
        // Query
21
 
        CString sHost;
22
 
        CSSockAddr::EAFRequire family;
23
 
 
24
 
        // Result
25
 
        int ares_status;
26
 
        CSSockAddr addr;
27
 
};
28
 
 
29
 
static ares_channel& GetAres() {
30
 
        static ares_channel m_ares;
31
 
        return m_ares;
32
 
}
33
 
#endif
34
 
 
35
 
CZNCSock::~CZNCSock() {
36
 
#ifdef HAVE_ARES
37
 
        if (m_dns_lookup) {
38
 
                m_dns_lookup->bSocketDead = true;
39
 
                if (m_dns_lookup->bLookupDone)
40
 
                        delete m_dns_lookup;
41
 
                m_dns_lookup = NULL;
42
 
        }
43
 
#endif
44
 
}
45
 
 
46
 
CSockManager::CSockManager() : TSocketManager<CZNCSock>() {
47
 
#ifdef HAVE_ARES
48
 
        int i = ares_init(&GetAres());
49
 
        if (i != ARES_SUCCESS) {
50
 
                CUtils::PrintError("Could not initialize c-ares: " + CString(ares_strerror(i)));
51
 
                exit(-1);
52
 
        }
53
 
        DEBUG("Successfully initialized c-ares");
54
 
#endif
55
 
}
56
 
 
57
 
CSockManager::~CSockManager() {
58
 
#ifdef HAVE_ARES
59
 
        ares_destroy(GetAres());
60
 
#endif
61
 
}
62
 
 
63
 
#ifdef HAVE_ARES
64
 
int CSockManager::Select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout)
65
 
{
66
 
        int ret;
67
 
        fd_set tmp;
68
 
 
69
 
        // Csocket sometimes can use NULL for writefds and c-ares doesn't like NULLs here
70
 
        if (writefds == NULL)
71
 
        {
72
 
                writefds = &tmp;
73
 
                FD_ZERO(writefds);
74
 
        }
75
 
 
76
 
        // We assume that nfds is already the max. number of sockets allowed by
77
 
        // the OS, so we don't need to update it here.
78
 
        ares_fds(GetAres(), readfds, writefds);
79
 
        ares_timeout(GetAres(), timeout, timeout);
80
 
 
81
 
        ret = ::select(nfds, readfds, writefds, exceptfds, timeout);
82
 
 
83
 
        ares_process(GetAres(), readfds, writefds);
84
 
 
85
 
        return ret;
86
 
}
87
 
 
88
 
void CZNCSock::ares_callback(void *lookup, int status, int timeout, struct hostent *h) {
89
 
        struct DNSLookup *p = (struct DNSLookup *) lookup;
90
 
        p->bLookupDone = true;
91
 
 
92
 
        DEBUG("DNS lookup done for " << p->sHost);
93
 
        if (p->bSocketDead) {
94
 
                delete p;
95
 
                return;
96
 
        }
97
 
 
98
 
        p->ares_status = status;
99
 
        if (!h) {
100
 
#ifdef HAVE_IPV6
101
 
                if (p->family == CSSockAddr::RAF_ANY) {
102
 
                        // Try an AAAA lookup
103
 
                        p->family = CSSockAddr::RAF_INET6;
104
 
                        DEBUG("Retrying with AAAA");
105
 
                        p->bLookupDone = false;
106
 
                        ares_gethostbyname(GetAres(), p->sHost.c_str(), p->family,
107
 
                                        ares_callback, p);
108
 
                        return;
109
 
                }
110
 
#endif
111
 
                if (status == ARES_SUCCESS)
112
 
                        p->ares_status = ARES_ENOTIMP;
113
 
                return;
114
 
        }
115
 
 
116
 
        if (h->h_addrtype == AF_INET && h->h_length == sizeof(in_addr)) {
117
 
                memcpy(p->addr.GetAddr(), h->h_addr_list[0], sizeof(in_addr));
118
 
                p->addr.SetIPv6(false);
119
 
        }
120
 
#ifdef HAVE_IPV6
121
 
        else if (h->h_addrtype == AF_INET6 && h->h_length == sizeof(in6_addr)) {
122
 
                memcpy(p->addr.GetAddr6(), h->h_addr_list[0], sizeof(in6_addr));
123
 
                p->addr.SetIPv6(true);
124
 
        }
125
 
#endif
126
 
        else
127
 
                DEBUG(__PRETTY_FUNCTION__ << ": Got unknown address with length " << h->h_length);
128
 
}
129
 
 
130
 
int CZNCSock::GetAddrInfo(const CS_STRING &sHostname, CSSockAddr &csSockAddr) {
131
 
        // If this is an ip address, no lookup is necessary
132
 
#ifdef HAVE_IPV6
133
 
        if (inet_pton(AF_INET6, sHostname.c_str(), csSockAddr.GetAddr6()) > 0) {
134
 
                csSockAddr.SetIPv6(true);
135
 
                SetIPv6(true);
136
 
                return 0;
137
 
        }
138
 
#endif
139
 
        if (inet_pton(AF_INET, sHostname.c_str(), csSockAddr.GetAddr()) > 0) {
140
 
                csSockAddr.SetIPv6(false);
141
 
                SetIPv6(false);
142
 
                return 0;
143
 
        }
144
 
 
145
 
        if (!m_dns_lookup) {
146
 
                DEBUG("New dns lookup for " << sHostname);
147
 
 
148
 
                m_dns_lookup = new struct DNSLookup;
149
 
                m_dns_lookup->bSocketDead = false;
150
 
                m_dns_lookup->bLookupDone = false;
151
 
                m_dns_lookup->sHost = sHostname;
152
 
                m_dns_lookup->ares_status = 0;
153
 
                m_dns_lookup->family = csSockAddr.GetAFRequire();
154
 
 
155
 
                CSSockAddr::EAFRequire family = csSockAddr.GetAFRequire();
156
 
                if (family == CSSockAddr::RAF_ANY) {
157
 
                        // post-1.6.0 c-ares (=current CVS versions) support
158
 
                        // lookups with AF_UNSPEC which means it first tries an
159
 
                        // AAAA lookup and then fails back to an A lookup.
160
 
                        // Older versions (= any version out there) just
161
 
                        // generate an "address family not supported" error
162
 
                        // message if you feed them, so we can't use this nice
163
 
                        // feature for now.
164
 
                        family = CSSockAddr::RAF_INET;
165
 
                }
166
 
                ares_gethostbyname(GetAres(), sHostname.c_str(), family,
167
 
                                ares_callback, m_dns_lookup);
168
 
        }
169
 
 
170
 
        if (m_dns_lookup->sHost != sHostname)
171
 
                // This *cannot* happen
172
 
                DEBUG(__PRETTY_FUNCTION__ << ": Query target for an active DNS query changed!");
173
 
 
174
 
        if (!m_dns_lookup->bLookupDone) {
175
 
                DEBUG("waiting for dns on [" << sHostname << "] to finish...");
176
 
                return EAGAIN;
177
 
        }
178
 
 
179
 
        if (m_dns_lookup->ares_status != ARES_SUCCESS) {
180
 
                DEBUG("Error while looking up [" << sHostname << "]: "
181
 
                                << ares_strerror(m_dns_lookup->ares_status));
182
 
                delete m_dns_lookup;
183
 
                m_dns_lookup = NULL;
184
 
                return ETIMEDOUT;
185
 
        }
186
 
 
187
 
#ifdef HAVE_IPV6
188
 
        memcpy(csSockAddr.GetAddr6(), m_dns_lookup->addr.GetAddr6(), sizeof(in6_addr));
189
 
#endif
190
 
        memcpy(csSockAddr.GetAddr(), m_dns_lookup->addr.GetAddr(), sizeof(in_addr));
191
 
        csSockAddr.SetIPv6(m_dns_lookup->addr.GetIPv6());
192
 
        SetIPv6(csSockAddr.GetIPv6());
193
 
 
194
 
        DEBUG("GetAddrInfo() done for " << sHostname.c_str());
195
 
 
196
 
        delete m_dns_lookup;
197
 
        m_dns_lookup = NULL;
198
 
 
199
 
        return 0;
200
 
}
201
 
#endif
 
10
#include "Modules.h"
 
11
#include "User.h"
 
12
#include "znc.h"
202
13
 
203
14
unsigned int CSockManager::GetAnonConnectionCount(const CString &sIP) const {
204
15
        const_iterator it;
205
16
        unsigned int ret = 0;
206
17
 
207
 
        for (it = begin(); it != end(); it++) {
 
18
        for (it = begin(); it != end(); ++it) {
208
19
                CZNCSock *pSock = *it;
209
20
                // Logged in CClients have "USR::<username>" as their sockname
210
 
                if (pSock->GetRemoteIP() == sIP && pSock->GetSockName().Left(5) != "USR::") {
 
21
                if (pSock->GetType() == Csock::INBOUND && pSock->GetRemoteIP() == sIP
 
22
                                && pSock->GetSockName().Left(5) != "USR::") {
211
23
                        ret++;
212
24
                }
213
25
        }
216
28
 
217
29
        return ret;
218
30
}
 
31
 
 
32
CS_STRING CZNCSock::ConvertAddress(void *addr, bool ipv6) {
 
33
        CString sRet = Csock::ConvertAddress(addr, ipv6);
 
34
        sRet.TrimPrefix("::ffff:");
 
35
        return sRet;
 
36
}
 
37
 
 
38
/////////////////// CSocket ///////////////////
 
39
CSocket::CSocket(CModule* pModule) : CZNCSock() {
 
40
        m_pModule = pModule;
 
41
        m_pModule->AddSocket(this);
 
42
        EnableReadLine();
 
43
        SetMaxBufferThreshold(10240);
 
44
}
 
45
 
 
46
CSocket::CSocket(CModule* pModule, const CString& sHostname, unsigned short uPort, int iTimeout) : CZNCSock(sHostname, uPort, iTimeout) {
 
47
        m_pModule = pModule;
 
48
        m_pModule->AddSocket(this);
 
49
        EnableReadLine();
 
50
        SetMaxBufferThreshold(10240);
 
51
}
 
52
 
 
53
CSocket::~CSocket() {
 
54
        CUser *pUser = NULL;
 
55
 
 
56
        // CWebSock could cause us to have a NULL pointer here
 
57
        if (m_pModule) {
 
58
                pUser = m_pModule->GetUser();
 
59
                m_pModule->UnlinkSocket(this);
 
60
        }
 
61
 
 
62
        if (pUser && !m_pModule->IsGlobal()) {
 
63
                pUser->AddBytesWritten(GetBytesWritten());
 
64
                pUser->AddBytesRead(GetBytesRead());
 
65
        } else {
 
66
                CZNC::Get().AddBytesWritten(GetBytesWritten());
 
67
                CZNC::Get().AddBytesRead(GetBytesRead());
 
68
        }
 
69
}
 
70
 
 
71
void CSocket::ReachedMaxBuffer() {
 
72
        DEBUG(GetSockName() << " == ReachedMaxBuffer()");
 
73
        PutModule("Some socket reached its max buffer limit and was closed!");
 
74
        Close();
 
75
}
 
76
 
 
77
void CSocket::SockError(int iErrno) {
 
78
        DEBUG(GetSockName() << " == SockError(" << strerror(iErrno) << ")");
 
79
        if (iErrno == EMFILE) {
 
80
                // We have too many open fds, this can cause a busy loop.
 
81
                Close();
 
82
        }
 
83
}
 
84
 
 
85
bool CSocket::ConnectionFrom(const CString& sHost, unsigned short uPort) {
 
86
        return CZNC::Get().AllowConnectionFrom(sHost);
 
87
}
 
88
 
 
89
bool CSocket::Connect(const CString& sHostname, unsigned short uPort, bool bSSL, unsigned int uTimeout) {
 
90
        CUser* pUser = m_pModule->GetUser();
 
91
        CString sSockName = "MOD::C::" + m_pModule->GetModName();
 
92
        CString sVHost;
 
93
 
 
94
        if (pUser) {
 
95
                sSockName += "::" + pUser->GetUserName();
 
96
                sVHost = m_pModule->GetUser()->GetVHost();
 
97
        }
 
98
 
 
99
        // Don't overwrite the socket name if one is already set
 
100
        if (!GetSockName().empty()) {
 
101
                sSockName = GetSockName();
 
102
        }
 
103
 
 
104
        return m_pModule->GetManager()->Connect(sHostname, uPort, sSockName, uTimeout, bSSL, sVHost, this);
 
105
}
 
106
 
 
107
bool CSocket::Listen(unsigned short uPort, bool bSSL, unsigned int uTimeout) {
 
108
        CUser* pUser = m_pModule->GetUser();
 
109
        CString sSockName = "MOD::L::" + m_pModule->GetModName();
 
110
 
 
111
        if (pUser) {
 
112
                sSockName += "::" + pUser->GetUserName();
 
113
        }
 
114
        // Don't overwrite the socket name if one is already set
 
115
        if (!GetSockName().empty()) {
 
116
                sSockName = GetSockName();
 
117
        }
 
118
 
 
119
        return m_pModule->GetManager()->ListenAll(uPort, sSockName, bSSL, SOMAXCONN, this);
 
120
}
 
121
 
 
122
bool CSocket::PutIRC(const CString& sLine) {
 
123
        return (m_pModule) ? m_pModule->PutIRC(sLine) : false;
 
124
}
 
125
 
 
126
bool CSocket::PutUser(const CString& sLine) {
 
127
        return (m_pModule) ? m_pModule->PutUser(sLine) : false;
 
128
}
 
129
 
 
130
bool CSocket::PutStatus(const CString& sLine) {
 
131
        return (m_pModule) ? m_pModule->PutStatus(sLine) : false;
 
132
}
 
133
 
 
134
bool CSocket::PutModule(const CString& sLine, const CString& sIdent, const CString& sHost) {
 
135
        return (m_pModule) ? m_pModule->PutModule(sLine, sIdent, sHost) : false;
 
136
}
 
137
bool CSocket::PutModNotice(const CString& sLine, const CString& sIdent, const CString& sHost) {
 
138
        return (m_pModule) ? m_pModule->PutModNotice(sLine, sIdent, sHost) : false;
 
139
}
 
140
 
 
141
void CSocket::SetModule(CModule* p) { m_pModule = p; }
 
142
CModule* CSocket::GetModule() const { return m_pModule; }
 
143
/////////////////// !CSocket ///////////////////