source: sources/src/toolsNetwork.cc @ 1464:3f6711617be1

Revision 1464:3f6711617be1, 16.2 KB checked in by niam, 22 months ago (diff)

{issue #58[resolved]} support for non-c++ exceptions

Line 
1/***************************************************************************
2 *            toolsNetwork.cc
3 *
4 *  Thu Sep 20 2005
5 *  Copyright  2005  Dmytro Milinevskyy
6 *  milinevskyy@gmail.com
7 ****************************************************************************/
8
9/*
10 *  This program is free software; you can redistribute it and/or modify
11 *  it under the terms of the GNU Lesser General Public License version 2.1 as published by
12 *  the Free Software Foundation;
13 *
14 *  This program is distributed in the hope that it will be useful,
15 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
16 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17 *  GNU Library General Public License for more details.
18 *
19 *  You should have received a copy of the GNU Lesser General Public License
20 *  along with this program; if not, write to the Free Software
21 *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
22 */
23
24/**
25 * vim indentation settings
26 * set tabstop=4
27 * set shiftwidth=4
28 */
29
30#include <libdodo/directives.h>
31
32#include <netdb.h>
33#include <errno.h>
34#include <string.h>
35#include <sys/socket.h>
36#include <netinet/in.h>
37#include <arpa/inet.h>
38#include <net/if.h>
39#include <sys/ioctl.h>
40#include <stdio.h>
41#include <unistd.h>
42
43#include <libdodo/toolsNetwork.h>
44#include <libdodo/toolsNetworkEx.h>
45#include <libdodo/types.h>
46#include <libdodo/toolsMisc.h>
47#include <libdodo/toolsString.h>
48#include <libdodo/ioNetworkConnection.h>
49#include <libdodo/ioNetworkExchange.h>
50#include <libdodo/ioNetworkClient.h>
51#include <libdodo/toolsCode.h>
52
53using namespace dodo::tools;
54
55network::__host__
56network::host(const dodo::string &host)
57{
58    hostent *ent = gethostbyname(host.data());
59
60    if (ent == NULL)
61        dodo_throw exception::basic(exception::MODULE_TOOLSNETWORK, NETWORKEX_HOST, exception::ERRNO_H_ERRNO, h_errno, hstrerror(h_errno), __LINE__, __FILE__);
62
63    __host__ info;
64    info.name = ent->h_name;
65
66    int i(0);
67
68    while (ent->h_aliases[i] != NULL)
69        info.aliases.push_back(ent->h_aliases[i++]);
70
71    i = 0;
72    char temp[INET6_ADDRSTRLEN];
73
74    while (ent->h_addr_list[i] != NULL) {
75        switch (ent->h_addrtype) {
76            case AF_INET:
77
78                if (inet_ntop(AF_INET, ent->h_addr_list[i], temp, INET_ADDRSTRLEN) == NULL) {
79                    ++i;
80
81                    continue;
82                }
83
84                break;
85
86            case AF_INET6:
87
88                if (inet_ntop(AF_INET6, ent->h_addr_list[i], temp, INET6_ADDRSTRLEN) == NULL) {
89                    ++i;
90
91                    continue;
92                }
93
94                break;
95        }
96
97        info.addresses.push_back(temp);
98        ++i;
99    }
100
101    return info;
102}
103
104//-------------------------------------------------------------------
105
106dodo::string
107network::hostPrimaryIp(const dodo::string &host)
108{
109    hostent *ent = gethostbyname(host.data());
110
111    if (ent == NULL)
112        dodo_throw exception::basic(exception::MODULE_TOOLSNETWORK, NETWORKEX_HOSTPRIMARYIP, exception::ERRNO_H_ERRNO, h_errno, hstrerror(h_errno), __LINE__, __FILE__);
113
114    char temp[INET6_ADDRSTRLEN];
115
116    if (ent->h_addr_list[0] != NULL) {
117        switch (ent->h_addrtype) {
118            case AF_INET:
119
120                if (inet_ntop(AF_INET, ent->h_addr_list[0], temp, INET_ADDRSTRLEN) == NULL)
121                    dodo_throw exception::basic(exception::MODULE_TOOLSNETWORK, NETWORKEX_HOSTPRIMARYIP, exception::ERRNO_H_ERRNO, h_errno, hstrerror(h_errno), __LINE__, __FILE__);
122
123                break;
124
125            case AF_INET6:
126
127                if (inet_ntop(AF_INET6, ent->h_addr_list[0], temp, INET6_ADDRSTRLEN) == NULL)
128                    dodo_throw exception::basic(exception::MODULE_TOOLSNETWORK, NETWORKEX_HOSTPRIMARYIP, exception::ERRNO_H_ERRNO, h_errno, hstrerror(h_errno), __LINE__, __FILE__);
129
130                break;
131        }
132    }
133
134    return temp;
135}
136
137//-------------------------------------------------------------------
138
139dodo::dodoStringArray
140network::interfacesNames()
141{
142    struct if_nameindex *ifaces = if_nameindex();
143    if (ifaces == NULL)
144        dodo_throw exception::basic(exception::MODULE_TOOLSNETWORK, NETWORKEX_INTERFACESNAMES, exception::ERRNO_ERRNO, errno, strerror(errno), __LINE__, __FILE__);
145
146    int i(-1);
147    dodoStringArray arr;
148
149    while (ifaces[++i].if_index != 0)
150        arr.push_back(ifaces[i].if_name);
151
152    if_freenameindex(ifaces);
153
154    return arr;
155}
156
157//-------------------------------------------------------------------
158
159network::__service__
160network::service(const dodo::string &host,
161                 const dodo::string &protocol)
162{
163    servent *ent = getservbyname(host.data(), protocol.data());
164
165    __service__ info;
166
167    if (ent == NULL)
168        return info;
169
170    info.name = ent->s_name;
171    info.port = ent->s_port;
172
173    int i(0);
174
175    while (ent->s_aliases[i] != NULL)
176        info.aliases.push_back(ent->s_aliases[i++]);
177
178    return info;
179}
180
181//-------------------------------------------------------------------
182
183network::__service__
184network::service(int              port,
185                 const dodo::string &protocol)
186{
187    servent *ent = getservbyport(port, protocol.data());
188
189    __service__ info;
190
191    if (ent == NULL)
192        return info;
193
194    info.name = ent->s_name;
195    info.port = ent->s_port;
196
197    int i(0);
198
199    while (ent->s_aliases[i] != NULL)
200        info.aliases.push_back(ent->s_aliases[i++]);
201
202    return info;
203}
204
205//-------------------------------------------------------------------
206
207network::__interface__
208network::interface(const dodo::string &interface)
209{
210    int socket = ::socket(PF_INET, SOCK_DGRAM, 0);
211    if (socket == -1)
212        dodo_throw exception::basic(exception::MODULE_TOOLSNETWORK, NETWORKEX_INTERFACE, exception::ERRNO_ERRNO, errno, strerror(errno), __LINE__, __FILE__);
213
214    ifreq ifr;
215    strcpy(ifr.ifr_name, interface.data());
216
217    __interface__ info;
218    char add[INET6_ADDRSTRLEN];
219
220    sockaddr_in sin;
221
222    if (::ioctl(socket, SIOCGIFADDR, &ifr) == -1)
223        dodo_throw exception::basic(exception::MODULE_TOOLSNETWORK, NETWORKEX_INTERFACE, exception::ERRNO_ERRNO, errno, strerror(errno), __LINE__, __FILE__);
224
225    memcpy((void *)&sin, &ifr.ifr_ifru.ifru_addr, sizeof(sockaddr));
226
227    if (inet_ntop(AF_INET, &sin.sin_addr, add, INET_ADDRSTRLEN) != NULL)
228        info.address = add;
229
230#ifdef __FreeBSD__
231#else
232    if (::ioctl(socket, SIOCGIFNETMASK, &ifr) == -1)
233        dodo_throw exception::basic(exception::MODULE_TOOLSNETWORK, NETWORKEX_INTERFACE, exception::ERRNO_ERRNO, errno, strerror(errno), __LINE__, __FILE__);
234
235    memcpy((void *)&sin, &ifr.ifr_ifru.ifru_netmask, sizeof(sockaddr));
236
237    if (inet_ntop(AF_INET, &sin.sin_addr, add, INET_ADDRSTRLEN) != NULL)
238        info.netmask = add;
239
240#endif
241
242    if (::ioctl(socket, SIOCGIFBRDADDR, &ifr) == -1)
243        dodo_throw exception::basic(exception::MODULE_TOOLSNETWORK, NETWORKEX_INTERFACE, exception::ERRNO_ERRNO, errno, strerror(errno), __LINE__, __FILE__);
244
245    memcpy((void *)&sin, &ifr.ifr_ifru.ifru_broadaddr, sizeof(sockaddr));
246
247    if (inet_ntop(AF_INET, &sin.sin_addr, add, INET_ADDRSTRLEN) != NULL)
248        info.broadcast = add;
249
250#ifdef __FreeBSD__
251#else
252    if (::ioctl(socket, SIOCGIFHWADDR, &ifr) == -1)
253        dodo_throw exception::basic(exception::MODULE_TOOLSNETWORK, NETWORKEX_INTERFACE, exception::ERRNO_ERRNO, errno, strerror(errno), __LINE__, __FILE__);
254
255    sprintf(add, "%.2X:%.2X:%.2X:%.2X:%.2X:%.2X", ifr.ifr_ifru.ifru_hwaddr.sa_data[0] & 0xff,
256            ifr.ifr_ifru.ifru_hwaddr.sa_data[1] & 0xff,
257            ifr.ifr_ifru.ifru_hwaddr.sa_data[2] & 0xff,
258            ifr.ifr_ifru.ifru_hwaddr.sa_data[3] & 0xff,
259            ifr.ifr_ifru.ifru_hwaddr.sa_data[4] & 0xff,
260            ifr.ifr_ifru.ifru_hwaddr.sa_data[5] & 0xff);
261#endif
262
263    info.hwaddr = add;
264
265    if (::ioctl(socket, SIOCGIFFLAGS, &ifr) == -1)
266        dodo_throw exception::basic(exception::MODULE_TOOLSNETWORK, NETWORKEX_INTERFACE, exception::ERRNO_ERRNO, errno, strerror(errno), __LINE__, __FILE__);
267
268    if (::close(socket) == -1)
269        dodo_throw exception::basic(exception::MODULE_TOOLSNETWORK, NETWORKEX_INTERFACE, exception::ERRNO_ERRNO, errno, strerror(errno), __LINE__, __FILE__);
270
271#ifdef __FreeBSD__
272    if (isSetFlag(ifr.ifr_ifru.ifru_flags[0], IFF_LOOPBACK))
273        info.loop = true;
274
275    if (isSetFlag(ifr.ifr_ifru.ifru_flags[0], IFF_UP))
276        info.up = true;
277
278#else
279    if (isSetFlag(IFF_LOOPBACK & ifr.ifr_ifru.ifru_flags, IFF_LOOPBACK))
280        info.loop = true;
281
282    if (isSetFlag(IFF_UP & ifr.ifr_ifru.ifru_flags, IFF_UP))
283        info.up = true;
284
285#endif
286
287    return info;
288}
289
290//-------------------------------------------------------------------
291
292dodo::string
293network::localName()
294{
295    dodo::string temp0;
296    char *temp1 = new char[256];
297
298    if (::gethostname(temp1, 255) == -1) {
299        delete [] temp1;
300
301        dodo_throw exception::basic(exception::MODULE_TOOLSNETWORK, NETWORKEX_LOCALNAME, exception::ERRNO_ERRNO, errno, strerror(errno), __LINE__, __FILE__);
302    }
303
304    temp0 = dodo::string(temp1);
305
306    delete [] temp1;
307
308    return temp0;
309}
310
311//-------------------------------------------------------------------
312
313void
314network::setLocalName(const dodo::string &host)
315{
316    if (::sethostname(host.data(), host.size()) == -1)
317        dodo_throw exception::basic(exception::MODULE_TOOLSNETWORK, NETWORKEX_SETLOCALNAME, exception::ERRNO_ERRNO, errno, strerror(errno), __LINE__, __FILE__);
318}
319
320//-------------------------------------------------------------------
321
322void
323network::mail(const dodo::string &to,
324              const dodo::string &subject,
325              const dodo::string &message,
326              const dodo::string &headers,
327              const dodo::string &path)
328{
329    FILE *sendmail = popen((path + " " + to).data(), "w");
330
331    if (sendmail == NULL)
332        dodo_throw exception::basic(exception::MODULE_TOOLSNETWORK, NETWORKEX_MAIL, exception::ERRNO_ERRNO, errno, strerror(errno), __LINE__, __FILE__);
333
334    fprintf(sendmail, "To: %s\n", to.data());
335    fprintf(sendmail, "Subject: %s\n", subject.data());
336    if (headers.size() > 0)
337        fprintf(sendmail, "%s\n", headers.data());
338    fprintf(sendmail, "\n%s\n", message.data());
339
340    if (pclose(sendmail) == -1)
341        dodo_throw exception::basic(exception::MODULE_TOOLSNETWORK, NETWORKEX_MAIL, exception::ERRNO_ERRNO, errno, strerror(errno), __LINE__, __FILE__);
342}
343
344//-------------------------------------------------------------------
345
346void
347network::mail(const dodo::string &host,
348              int              port,
349              const dodo::string &to,
350              const dodo::string &from,
351              const dodo::string &subject,
352              const dodo::string &message,
353              const dodo::string &login,
354              const dodo::string &pass,
355              const dodo::string &headers)
356{
357    using namespace io::network;
358
359    enum mailAuthEnum {
360        SMTPAUTH_CRAMMD5 = 2,
361        SMTPAUTH_LOGIN = 4,
362        SMTPAUTH_PLAIN = 8
363    };
364
365    unsigned short authType = 0;
366
367    bool auth = login.size() > 0 ? true : false;
368
369    short family = connection::PROTOCOL_FAMILY_IPV4;
370    if (host.find(":") != dodo::string::POSITION_END)
371        family = connection::PROTOCOL_FAMILY_IPV6;
372
373    exchange ex;
374    client net(family, connection::TRANSFER_STREAM);
375
376    net.connect(host, port, ex);
377
378    dodo::string mess;
379
380    mess = ex.readString();
381    ex.writeString("EHLO " + network::localName() + "\r\n");
382    mess = ex.readString();
383
384    if (string::stringToI(dodo::string(mess.data(), 3)) != 250)
385        dodo_throw exception::basic(exception::MODULE_TOOLSNETWORK, NETWORKEX_MAIL, exception::ERRNO_LIBDODO, NETWORKEX_BADMAILHELO, TOOLSNETWORKEX_BADMAILHELO_STR, __LINE__, __FILE__);
386
387    if (auth) {
388        if (string::contains(mess, "CRAM-MD5"))
389            addFlag(authType, SMTPAUTH_CRAMMD5);
390
391        if (string::contains(mess, "LOGIN"))
392            addFlag(authType, SMTPAUTH_LOGIN);
393
394        if (string::contains(mess, "PLAIN"))
395            addFlag(authType, SMTPAUTH_PLAIN);
396    }
397
398    if (auth) {
399        if (isSetFlag(authType, SMTPAUTH_CRAMMD5)) {
400            ex.writeString("AUTH CRAM-MD5\r\n");
401            mess = ex.readString();
402
403            if (string::stringToI(dodo::string(mess.data(), 3)) != 334)
404                dodo_throw exception::basic(exception::MODULE_TOOLSNETWORK, NETWORKEX_MAIL, exception::ERRNO_ERRNO, NETWORKEX_BADMAILAUTH, TOOLSNETWORKEX_BADMAILAUTH_STR, __LINE__, __FILE__);
405
406            dodo::string ticket = code::decodeBase64(dodo::string(mess.data() + 4, mess.size() - 4));
407
408            dodo::string md5pass;
409            if (pass.size() > 64)
410                md5pass = code::MD5(pass);
411            else
412                md5pass = pass;
413
414            unsigned char ipad[65];
415            unsigned char opad[65];
416
417            memset(ipad, 0, 65);
418            memset(opad, 0, 65);
419
420            memcpy(ipad, md5pass.data(), md5pass.size());
421            memcpy(opad, md5pass.data(), md5pass.size());
422
423            for (short i = 0; i < 64; ++i) {
424                ipad[i] ^= 0x36;
425                opad[i] ^= 0x5c;
426            }
427
428            code::__MD5Context__ context;
429            unsigned char digest[16];
430
431            code::MD5Init(&context);
432            code::MD5Update(&context, ipad, 64);
433            code::MD5Update(&context, (unsigned char *)ticket.data(), ticket.size());
434            code::MD5Final(digest, &context);
435
436            code::MD5Init(&context);
437            code::MD5Update(&context, opad, 64);
438            code::MD5Update(&context, digest, 16);
439            code::MD5Final(digest, &context);
440
441            md5pass = code::binToHex(dodo::string((char *)&digest, 16));
442
443            ex.writeString(code::encodeBase64(login + " " + md5pass) + "\r\n");
444            mess = ex.readString();
445
446            if (string::stringToI(dodo::string(mess.data(), 3)) != 235)
447                dodo_throw exception::basic(exception::MODULE_TOOLSNETWORK, NETWORKEX_MAIL, exception::ERRNO_ERRNO, NETWORKEX_BADMAILAUTH, TOOLSNETWORKEX_BADMAILAUTH_STR, __LINE__, __FILE__);
448        } else {
449            if (isSetFlag(authType, SMTPAUTH_LOGIN)) {
450                ex.writeString("AUTH LOGIN\r\n");
451                mess = ex.readString();
452
453                if (string::stringToI(dodo::string(mess.data(), 3)) != 334)
454                    dodo_throw exception::basic(exception::MODULE_TOOLSNETWORK, NETWORKEX_MAIL, exception::ERRNO_ERRNO, NETWORKEX_BADMAILAUTH, TOOLSNETWORKEX_BADMAILAUTH_STR, __LINE__, __FILE__);
455
456                ex.writeString(code::encodeBase64(login) + "\r\n");
457                mess = ex.readString();
458
459                if (string::stringToI(dodo::string(mess.data(), 3)) != 334)
460                    dodo_throw exception::basic(exception::MODULE_TOOLSNETWORK, NETWORKEX_MAIL, exception::ERRNO_ERRNO, NETWORKEX_BADMAILAUTH, TOOLSNETWORKEX_BADMAILAUTH_STR, __LINE__, __FILE__);
461
462                ex.writeString(code::encodeBase64(pass) + "\r\n");
463                mess = ex.readString();
464
465                if (string::stringToI(dodo::string(mess.data(), 3)) != 235)
466                    dodo_throw exception::basic(exception::MODULE_TOOLSNETWORK, NETWORKEX_MAIL, exception::ERRNO_ERRNO, NETWORKEX_BADMAILAUTH, TOOLSNETWORKEX_BADMAILAUTH_STR, __LINE__, __FILE__);
467            } else {
468                if (isSetFlag(authType, SMTPAUTH_PLAIN)) {
469                    ex.writeString("AUTH PLAIN" + code::encodeBase64(login + "\0" + login + "\0" + pass) + "\r\n");
470                    mess = ex.readString();
471
472                    if (string::stringToI(dodo::string(mess.data(), 3)) != 334)
473                        dodo_throw exception::basic(exception::MODULE_TOOLSNETWORK, NETWORKEX_MAIL, exception::ERRNO_ERRNO, NETWORKEX_BADMAILAUTH, TOOLSNETWORKEX_BADMAILAUTH_STR, __LINE__, __FILE__);
474                }
475            }
476        }
477    }
478
479    ex.writeString("MAIL FROM: <" + from + ">\r\n");
480    mess = ex.readString();
481
482    dodoStringArray pock = misc::split(to, ",");
483
484    dodoStringArray::iterator i = pock.begin(), j = pock.end();
485    for (; i != j; ++i) {
486        ex.writeString("RCPT TO: <" + *i + ">\r\n");
487        mess = ex.readString();
488    }
489
490    ex.writeString("DATA\r\n");
491    mess = ex.readString();
492
493    ex.writeString("To: " + to + "\r\n");
494    ex.writeString("From: " + from + "\r\n");
495    ex.writeString("X-Mailer: " PACKAGE_NAME "/" PACKAGE_VERSION "\r\n");
496    ex.writeString("Subject: " + subject  + "\r\n");
497    ex.writeString(headers);
498    ex.writeString(message);
499    ex.writeString("\r\n.\r\n");
500    ex.writeString("QUIT\r\n");
501}
502
503//-------------------------------------------------------------------
504
Note: See TracBrowser for help on using the repository browser.