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 }