File indexing completed on 2025-01-05 04:37:30

0001 /*
0002     SPDX-FileCopyrightText: 2005 Joris Guisson <joris.guisson@gmail.com>
0003 
0004     SPDX-License-Identifier: GPL-2.0-or-later
0005 */
0006 
0007 #include "functions.h"
0008 #include <arpa/inet.h>
0009 #include <errno.h>
0010 #include <gcrypt.h>
0011 #include <netdb.h>
0012 #include <netinet/in.h>
0013 #include <sys/resource.h>
0014 #include <sys/socket.h>
0015 #include <sys/time.h>
0016 #include <sys/types.h>
0017 #include <unistd.h>
0018 
0019 #include <QDir>
0020 #include <QMimeDatabase>
0021 #include <QMimeType>
0022 #include <QNetworkInterface>
0023 #include <QTime>
0024 
0025 #include <KFormat>
0026 #include <KLocalizedString>
0027 
0028 #include <interfaces/torrentinterface.h>
0029 #include <util/signalcatcher.h>
0030 
0031 #include "error.h"
0032 #include "log.h"
0033 
0034 namespace bt
0035 {
0036 bool IsMultimediaFile(const QString &filename)
0037 {
0038     QMimeType ptr = QMimeDatabase().mimeTypeForFile(filename);
0039     QString name = ptr.name();
0040     return name.startsWith(QLatin1String("audio")) || name.startsWith(QLatin1String("video")) || name == QLatin1String("application/ogg");
0041 }
0042 
0043 QString DirSeparator()
0044 {
0045     // QString tmp;
0046     // tmp.append(QDir::separator());
0047     return QStringLiteral("/");
0048 }
0049 
0050 void UpdateCurrentTime()
0051 {
0052     global_time_stamp = Now();
0053 }
0054 
0055 TimeStamp global_time_stamp = 0;
0056 
0057 Uint64 Now()
0058 {
0059     struct timeval tv;
0060     gettimeofday(&tv, nullptr);
0061     global_time_stamp = (Uint64)tv.tv_sec * 1000 + (Uint64)tv.tv_usec * 0.001;
0062     return global_time_stamp;
0063 }
0064 
0065 Uint32 MaxOpenFiles()
0066 {
0067     static Uint32 max_open = 0;
0068     if (max_open == 0) {
0069         struct rlimit lim;
0070         getrlimit(RLIMIT_NOFILE, &lim);
0071         max_open = lim.rlim_cur;
0072     }
0073 
0074     return max_open;
0075 }
0076 
0077 Uint32 CurrentOpenFiles()
0078 {
0079     return 0;
0080     /*
0081     //return 0;
0082     #ifdef Q_OS_LINUX
0083     QDir dir(QString("/proc/%1/fd").arg(getpid()));
0084     return dir.count();
0085     #else
0086     return 0;
0087     #endif
0088     */
0089 }
0090 
0091 bool OpenFileAllowed()
0092 {
0093     const Uint32 headroom = 50;
0094     Uint32 max_open = MaxOpenFiles();
0095     if (max_open == 0)
0096         return true;
0097     else
0098         return max_open - CurrentOpenFiles() > headroom;
0099 }
0100 
0101 bool MaximizeLimits()
0102 {
0103     // first get the current limits
0104     struct rlimit lim;
0105     getrlimit(RLIMIT_NOFILE, &lim);
0106 
0107     if (lim.rlim_cur != lim.rlim_max) {
0108         Out(SYS_GEN | LOG_DEBUG) << "Current limit for number of files : " << lim.rlim_cur << " (" << lim.rlim_max << " max)" << endl;
0109         lim.rlim_cur = lim.rlim_max;
0110         if (setrlimit(RLIMIT_NOFILE, &lim) < 0) {
0111             Out(SYS_GEN | LOG_DEBUG) << "Failed to maximize file limit : " << QString::fromUtf8(strerror(errno)) << endl;
0112             return false;
0113         }
0114     } else {
0115         Out(SYS_GEN | LOG_DEBUG) << "File limit already at maximum " << endl;
0116     }
0117 
0118     getrlimit(RLIMIT_DATA, &lim);
0119     if (lim.rlim_cur != lim.rlim_max) {
0120         Out(SYS_GEN | LOG_DEBUG) << "Current limit for data size : " << lim.rlim_cur << " (" << lim.rlim_max << " max)" << endl;
0121         lim.rlim_cur = lim.rlim_max;
0122         if (setrlimit(RLIMIT_DATA, &lim) < 0) {
0123             Out(SYS_GEN | LOG_DEBUG) << "Failed to maximize data limit : " << QString::fromUtf8(strerror(errno)) << endl;
0124             return false;
0125         }
0126     } else {
0127         Out(SYS_GEN | LOG_DEBUG) << "Data limit already at maximum " << endl;
0128     }
0129 
0130     return true;
0131 }
0132 
0133 static QString net_iface = QString();
0134 
0135 void SetNetworkInterface(const QString &iface)
0136 {
0137     net_iface = iface;
0138 }
0139 
0140 QString NetworkInterface()
0141 {
0142     return net_iface;
0143 }
0144 
0145 QString NetworkInterfaceIPAddress(const QString &iface)
0146 {
0147     QNetworkInterface ni = QNetworkInterface::interfaceFromName(iface);
0148     if (!ni.isValid())
0149         return QString();
0150 
0151     QList<QNetworkAddressEntry> addr_list = ni.addressEntries();
0152     if (addr_list.count() == 0)
0153         return QString();
0154     else
0155         return addr_list.front().ip().toString();
0156 }
0157 
0158 QStringList NetworkInterfaceIPAddresses(const QString &iface)
0159 {
0160     QNetworkInterface ni = QNetworkInterface::interfaceFromName(iface);
0161     if (!ni.isValid())
0162         return QStringList();
0163 
0164     QStringList ips;
0165     const QList<QNetworkAddressEntry> addr_list = ni.addressEntries();
0166     for (const QNetworkAddressEntry &entry : addr_list) {
0167         ips << entry.ip().toString();
0168     }
0169 
0170     return ips;
0171 }
0172 
0173 QString CurrentIPv6Address()
0174 {
0175     QNetworkInterface ni = QNetworkInterface::interfaceFromName(net_iface);
0176     if (!ni.isValid()) {
0177         const QList<QHostAddress> addrs = QNetworkInterface::allAddresses();
0178         for (const QHostAddress &addr : addrs) {
0179             if (addr.protocol() == QAbstractSocket::IPv6Protocol && addr != QHostAddress::LocalHostIPv6
0180                 && !addr.isInSubnet(QHostAddress(QStringLiteral("FE80::")), 64))
0181                 return addr.toString();
0182         }
0183     } else {
0184         const QList<QNetworkAddressEntry> addrs = ni.addressEntries();
0185         for (const QNetworkAddressEntry &entry : addrs) {
0186             QHostAddress addr = entry.ip();
0187             if (addr.protocol() == QAbstractSocket::IPv6Protocol && addr != QHostAddress::LocalHostIPv6
0188                 && !addr.isInSubnet(QHostAddress(QStringLiteral("FE80::")), 64))
0189                 return addr.toString();
0190         }
0191     }
0192 
0193     return QString();
0194 }
0195 
0196 QString BytesToString(Uint64 bytes)
0197 {
0198     static KFormat format;
0199     return format.formatByteSize(bytes, 2);
0200 }
0201 
0202 QString BytesPerSecToString(double speed)
0203 {
0204     static KFormat format;
0205     return i18n("%1/s", format.formatByteSize(speed, 2));
0206 }
0207 
0208 QString DurationToString(Uint32 nsecs)
0209 {
0210     int ndays = nsecs / 86400;
0211     QTime t = QTime(0, 0, 0, 0).addSecs(nsecs % 86400);
0212     QString s;
0213     if (ndays > 0)
0214         s = i18np("1 day ", "%1 days ", ndays);
0215     else if (t.hour())
0216         s = t.toString();
0217     else
0218         s = t.toString(QStringLiteral("mm:ss"));
0219     return s;
0220 }
0221 
0222 double Percentage(const TorrentStats &s)
0223 {
0224     if (s.bytes_left_to_download == 0) {
0225         return 100.0;
0226     } else {
0227         if (s.total_bytes_to_download == 0) {
0228             return 100.0;
0229         } else {
0230             double perc = 100.0 - ((double)s.bytes_left_to_download / s.total_bytes_to_download) * 100.0;
0231             if (perc > 100.0)
0232                 perc = 100.0;
0233             else if (perc > 99.9)
0234                 perc = 99.9;
0235             else if (perc < 0.0)
0236                 perc = 0.0;
0237 
0238             return perc;
0239         }
0240     }
0241 }
0242 
0243 #ifdef Q_WS_WIN
0244 static bool InitWindowsSocketsAPI()
0245 {
0246     static bool initialized = false;
0247     if (initialized)
0248         return true;
0249 
0250     WSADATA wsaData;
0251     WORD wVersionRequested = MAKEWORD(2, 2);
0252     int err = WSAStartup(wVersionRequested, &wsaData);
0253     if (err != 0)
0254         return false;
0255 
0256     initialized = true;
0257     return true;
0258 }
0259 #endif
0260 
0261 static bool InitGCrypt()
0262 {
0263     static bool initialized = false;
0264     if (initialized)
0265         return true;
0266 
0267     // If already initialized, don't do anything
0268     if (gcry_control(GCRYCTL_INITIALIZATION_FINISHED_P)) {
0269         initialized = true;
0270         return true;
0271     }
0272 
0273     if (!gcry_check_version("1.4.5")) {
0274         Out(SYS_GEN | LOG_NOTICE) << "Failed to initialize libgcrypt" << endl;
0275         return false;
0276     }
0277     /* Disable secure memory. */
0278     gcry_control(GCRYCTL_DISABLE_SECMEM, 0);
0279     gcry_control(GCRYCTL_INITIALIZATION_FINISHED, 0);
0280     initialized = true;
0281     return true;
0282 }
0283 
0284 bool InitLibKTorrent()
0285 {
0286     MaximizeLimits();
0287     bool ret = InitGCrypt();
0288 #ifdef Q_WS_WIN
0289     ret = InitWindowsSocketsAPI() && ret;
0290 #endif
0291     return ret;
0292 }
0293 
0294 }