MythTV master
mythmiscutil.cpp
Go to the documentation of this file.
1#include "mythmiscutil.h"
2
3// C++ headers
4#include <array>
5#include <cerrno>
6#include <cstdlib>
7#include <iostream>
8#include <thread>
9
10// POSIX
11#include <unistd.h>
12#include <fcntl.h>
13#include <sched.h>
14#include <sys/stat.h> // for umask, chmod
15
16// System specific C headers
17#include "compat.h"
18#include <QtGlobal>
19#if QT_VERSION >= QT_VERSION_CHECK(6,5,0)
20#include <QtEnvironmentVariables>
21#include <QtProcessorDetection>
22#include <QtSystemDetection>
23#endif
24
25#ifdef Q_OS_LINUX
26#include <sys/sysinfo.h>
27#endif
28
29#ifdef Q_OS_DARWIN
30#include <mach/mach.h>
31#endif
32
33#ifdef Q_OS_BSD4
34#include <sys/sysctl.h>
35#endif
36
37// Qt headers
38#include <QReadWriteLock>
39#include <QNetworkProxy>
40#include <QStringList>
41#include <QDataStream>
42#include <QUdpSocket>
43#include <QFileInfo>
44#include <QFile>
45#include <QDir>
46#include <QUrl>
47#include <QHostAddress>
48#include <QRegularExpression>
49#include <QRegularExpressionMatchIterator>
50
51// Myth headers
52#include "mythcorecontext.h"
53#include "exitcodes.h"
54#include "mythlogging.h"
55#include "mythsocket.h"
56#include "filesysteminfo.h"
57#include "mythsystemlegacy.h"
58
59
64bool getUptime(std::chrono::seconds &uptime)
65{
66#ifdef Q_OS_LINUX
67 struct sysinfo sinfo {};
68 if (sysinfo(&sinfo) == -1)
69 {
70 LOG(VB_GENERAL, LOG_ERR, "sysinfo() error");
71 return false;
72 }
73 uptime = std::chrono::seconds(sinfo.uptime);
74
75#elif defined(Q_OS_BSD4)
76 std::array<int,2> mib { CTL_KERN, KERN_BOOTTIME };
77 struct timeval bootTime;
78 size_t len = 0;
79
80 // Uptime is calculated. Get this machine's boot time
81 // and subtract it from the current machine time
82 len = sizeof(bootTime);
83 if (sysctl(mib.data(), 2, &bootTime, &len, nullptr, 0) == -1)
84 {
85 LOG(VB_GENERAL, LOG_ERR, "sysctl() error");
86 return false;
87 }
88 uptime = std::chrono::seconds(time(nullptr) - bootTime.tv_sec);
89#elif defined(Q_OS_WINDOWS)
90 uptime = std::chrono::seconds(::GetTickCount() / 1000);
91#else
92 // Hmmm. Not Linux, not FreeBSD or Darwin. What else is there :-)
93 LOG(VB_GENERAL, LOG_NOTICE, "Unknown platform. How do I get the uptime?");
94 return false;
95#endif
96
97 return true;
98}
99
107bool getMemStats([[maybe_unused]] int &totalMB,
108 [[maybe_unused]] int &freeMB,
109 [[maybe_unused]] int &totalVM,
110 [[maybe_unused]] int &freeVM)
111{
112#ifdef Q_OS_LINUX
113 static constexpr size_t MB { 1024LL * 1024 };
114 struct sysinfo sinfo {};
115 if (sysinfo(&sinfo) == -1)
116 {
117 LOG(VB_GENERAL, LOG_ERR,
118 "getMemStats(): Error, sysinfo() call failed.");
119 return false;
120 }
121
122 totalMB = (int)((sinfo.totalram * sinfo.mem_unit)/MB);
123 freeMB = (int)((sinfo.freeram * sinfo.mem_unit)/MB);
124 totalVM = (int)((sinfo.totalswap * sinfo.mem_unit)/MB);
125 freeVM = (int)((sinfo.freeswap * sinfo.mem_unit)/MB);
126 return true;
127#elif defined(Q_OS_DARWIN)
128 mach_port_t mp = 0;
129 mach_msg_type_number_t count = 0;
130 vm_size_t pageSize = 0;
131 vm_statistics_data_t s;
132
133 mp = mach_host_self();
134
135 // VM page size
136 if (host_page_size(mp, &pageSize) != KERN_SUCCESS)
137 pageSize = 4096; // If we can't look it up, 4K is a good guess
138
139 count = HOST_VM_INFO_COUNT;
140 if (host_statistics(mp, HOST_VM_INFO,
141 (host_info_t)&s, &count) != KERN_SUCCESS)
142 {
143 LOG(VB_GENERAL, LOG_ERR, "getMemStats(): Error, "
144 "failed to get virtual memory statistics.");
145 return false;
146 }
147
148 pageSize >>= 10; // This gives usages in KB
149 totalMB = (s.active_count + s.inactive_count +
150 s.wire_count + s.free_count) * pageSize / 1024;
151 freeMB = s.free_count * pageSize / 1024;
152
153
154 // This is a real hack. I have not found a way to ask the kernel how much
155 // swap it is using, and the dynamic_pager daemon doesn't even seem to be
156 // able to report what filesystem it is using for the swapfiles. So, we do:
157 {
158 auto fsInfo = FileSystemInfo(QString(), "/private/var/vm");
159 totalVM = (int)(fsInfo.getTotalSpace() >> 10);
160 freeVM = (int)(fsInfo.getFreeSpace() >> 10);
161 }
162 return true;
163#else
164 return false;
165#endif
166}
167
175{
176#if !defined(Q_OS_WINDOWS) && !defined(Q_OS_ANDROID)
177 loadArray loads {};
178 if (getloadavg(loads.data(), loads.size()) != -1)
179 return loads;
180#endif
181 return {-1, -1, -1};
182}
183
185{
186 QStringList strlist(QString("QUERY_LOAD"));
187
188 if (gCoreContext->SendReceiveStringList(strlist) && strlist.size() >= 3)
189 {
190 load[0] = strlist[0].toDouble();
191 load[1] = strlist[1].toDouble();
192 load[2] = strlist[2].toDouble();
193 return true;
194 }
195
196 return false;
197}
198
199bool RemoteGetUptime(std::chrono::seconds &uptime)
200{
201 QStringList strlist(QString("QUERY_UPTIME"));
202
203 if (!gCoreContext->SendReceiveStringList(strlist) || strlist.isEmpty())
204 return false;
205
206 if (strlist[0].isEmpty() || !strlist[0].at(0).isNumber())
207 return false;
208
209 if (sizeof(std::chrono::seconds::rep) == sizeof(long long))
210 uptime = std::chrono::seconds(strlist[0].toLongLong());
211 else if (sizeof(std::chrono::seconds::rep) == sizeof(long))
212 uptime = std::chrono::seconds(strlist[0].toLong());
213 else if (sizeof(std::chrono::seconds::rep) == sizeof(int))
214 uptime = std::chrono::seconds(strlist[0].toInt());
215
216 return true;
217}
218
219bool RemoteGetMemStats(int &totalMB, int &freeMB, int &totalVM, int &freeVM)
220{
221 QStringList strlist(QString("QUERY_MEMSTATS"));
222
223 if (gCoreContext->SendReceiveStringList(strlist) && strlist.size() >= 4)
224 {
225 totalMB = strlist[0].toInt();
226 freeMB = strlist[1].toInt();
227 totalVM = strlist[2].toInt();
228 freeVM = strlist[3].toInt();
229 return true;
230 }
231
232 return false;
233}
234
249bool ping(const QString &host, std::chrono::milliseconds timeout)
250{
251#ifdef Q_OS_WINDOWS
252 QString cmd = QString("%systemroot%\\system32\\ping.exe -w %1 -n 1 %2>NUL")
253 .arg(timeout.count()) .arg(host);
254
257#else
258 QString addrstr =
260 QHostAddress addr = QHostAddress(addrstr);
261#if defined(Q_OS_FREEBSD) || defined(Q_OS_DARWIN)
262 QString timeoutparam("-t");
263#else
264 // Linux, NetBSD, OpenBSD
265 QString timeoutparam("-w");
266#endif // UNIX-like
267 QString pingcmd =
268 addr.protocol() == QAbstractSocket::IPv6Protocol ? "ping6" : "ping";
269 QString cmd = QString("%1 %2 %3 -c 1 %4 >/dev/null 2>&1")
270 .arg(pingcmd, timeoutparam,
271 QString::number(duration_cast<std::chrono::seconds>(timeout).count()),
272 host);
273
276#endif // Q_OS_WINDOWS
277}
278
282bool telnet(const QString &host, int port)
283{
284 auto *s = new MythSocket();
285
286 bool connected = s->ConnectToHost(host, port);
287 s->DecrRef();
288
289 return connected;
290}
291
313long long MythFile::copy(QFile &dst, QFile &src, uint block_size)
314{
315 uint buflen = (block_size < 1024) ? (16 * 1024) : block_size;
316 char *buf = new char[buflen];
317 bool odst = false;
318 bool osrc = false;
319
320 if (!buf)
321 return -1LL;
322
323 if (!dst.isWritable() && !dst.isOpen())
324 {
325 odst = dst.open(QIODevice::Unbuffered |
326 QIODevice::WriteOnly |
327 QIODevice::Truncate);
328 }
329
330 if (!src.isReadable() && !src.isOpen())
331 osrc = src.open(QIODevice::Unbuffered|QIODevice::ReadOnly);
332
333 bool ok = dst.isWritable() && src.isReadable();
334 long long total_bytes = 0LL;
335 while (ok)
336 {
337 long long off = 0;
338 long long rlen = src.read(buf, buflen);
339 if (rlen<0)
340 {
341 LOG(VB_GENERAL, LOG_ERR, "read error");
342 ok = false;
343 break;
344 }
345 if (rlen==0)
346 break;
347
348 total_bytes += rlen;
349
350 while ((rlen-off>0) && ok)
351 {
352 long long wlen = dst.write(buf + off, rlen - off);
353 if (wlen>=0)
354 off+= wlen;
355 if (wlen<0)
356 {
357 LOG(VB_GENERAL, LOG_ERR, "write error");
358 ok = false;
359 }
360 }
361 }
362 delete[] buf;
363
364 if (odst)
365 dst.close();
366
367 if (osrc)
368 src.close();
369
370 return ok ? total_bytes : -1LL;
371}
372
373QString createTempFile(QString name_template, bool dir)
374{
375 int ret = -1;
376
377#ifdef Q_OS_WINDOWS
378 char temppath[MAX_PATH] = ".";
379 char tempfilename[MAX_PATH] = "";
380 // if GetTempPath fails, use current dir
381 GetTempPathA(MAX_PATH, temppath);
382 if (GetTempFileNameA(temppath, "mth", 0, tempfilename))
383 {
384 if (dir)
385 {
386 // GetTempFileNameA creates the file, so delete it before mkdir
387 unlink(tempfilename);
388 ret = mkdir(tempfilename);
389 }
390 else
391 ret = open(tempfilename, O_CREAT | O_RDWR, S_IREAD | S_IWRITE);
392 }
393 QString tmpFileName(tempfilename);
394#else
395 QByteArray safe_name_template = name_template.toLatin1();
396 std::string ctemplate = safe_name_template.constData();
397
398 if (dir)
399 {
400 ret = (mkdtemp(ctemplate.data())) ? 0 : -1;
401 }
402 else
403 {
404 mode_t cur_umask = umask(S_IRWXO | S_IRWXG);
405 ret = mkstemp(ctemplate.data());
406 umask(cur_umask);
407 }
408
409 QString tmpFileName = QString::fromStdString(ctemplate);
410#endif
411
412 if (ret == -1)
413 {
414 LOG(VB_GENERAL, LOG_ERR, QString("createTempFile(%1), Error ")
415 .arg(name_template) + ENO);
416 return name_template;
417 }
418
419 if (!dir && (ret >= 0))
420 close(ret);
421
422 return tmpFileName;
423}
424
443bool makeFileAccessible(const QString& filename)
444{
445 QByteArray fname = filename.toLatin1();
446 int ret = chmod(fname.constData(), 0666);
447 if (ret == -1)
448 {
449 LOG(VB_GENERAL, LOG_ERR, QString("Unable to change permissions on file. (%1)").arg(filename));
450 return false;
451 }
452 return true;
453}
454
458QString getResponse(const QString &query, const QString &def)
459{
460 QByteArray tmp = query.toLocal8Bit();
461 std::cout << tmp.constData();
462
463 tmp = def.toLocal8Bit();
464 if (!def.isEmpty())
465 std::cout << " [" << tmp.constData() << "] ";
466 else
467 std::cout << " ";
468
469 if (!isatty(fileno(stdin)) || !isatty(fileno(stdout)))
470 {
471 std::cout << "\n[console is not interactive, using default '"
472 << tmp.constData() << "']\n";
473 return def;
474 }
475
476 QTextStream stream(stdin);
477 QString qresponse = stream.readLine();
478
479 if (qresponse.isEmpty())
480 qresponse = def;
481
482 return qresponse;
483}
484
488int intResponse(const QString &query, int def)
489{
490 QString str_resp = getResponse(query, QString("%1").arg(def));
491 if (str_resp.isEmpty())
492 return def;
493 bool ok = false;
494 int resp = str_resp.toInt(&ok);
495 return (ok ? resp : def);
496}
497
498
499QString getSymlinkTarget(const QString &start_file,
500 QStringList *intermediaries,
501 unsigned maxLinks)
502{
503#if 0
504 LOG(VB_GENERAL, LOG_DEBUG,
505 QString("getSymlinkTarget('%1', 0x%2, %3)")
506 .arg(start_file).arg((uint64_t)intermediaries,0,16)
507 .arg(maxLinks));
508#endif
509
510 QString link;
511 QString cur_file = start_file;
512 QFileInfo fi(cur_file);
513
514 if (intermediaries)
515 {
516 intermediaries->clear();
517 intermediaries->push_back(start_file);
518 }
519
520 for (uint i = 0; (i <= maxLinks) && fi.isSymLink() &&
521 !(link = fi.symLinkTarget()).isEmpty(); i++)
522 {
523 cur_file = (link[0] == '/') ?
524 link : // absolute link
525 fi.absoluteDir().absolutePath() + "/" + link; // relative link
526
527 if (intermediaries && !intermediaries->contains(cur_file))
528 intermediaries->push_back(cur_file);
529
530 fi = QFileInfo(cur_file);
531 }
532
533#if 0
534 if (intermediaries)
535 {
536 for (uint i = 0; i < intermediaries->size(); i++)
537 {
538 LOG(VB_GENERAL, LOG_DEBUG, QString(" inter%1: %2")
539 .arg(i).arg((*intermediaries)[i]));
540 }
541 }
542
543 LOG(VB_GENERAL, LOG_DEBUG,
544 QString("getSymlinkTarget() -> '%1'")
545 .arg((!fi.isSymLink()) ? cur_file : QString()));
546#endif
547
548 return (!fi.isSymLink()) ? cur_file : QString();
549}
550
551bool IsMACAddress(const QString& MAC)
552{
553 QStringList tokens = MAC.split(':');
554 if (tokens.size() != 6)
555 {
556 LOG(VB_NETWORK, LOG_ERR,
557 QString("IsMACAddress(%1) = false, doesn't have 6 parts").arg(MAC));
558 return false;
559 }
560
561 for (int y = 0; y < 6; y++)
562 {
563 if (tokens[y].isEmpty())
564 {
565 LOG(VB_NETWORK, LOG_ERR,
566 QString("IsMACAddress(%1) = false, part #%2 is empty.")
567 .arg(MAC).arg(y));
568 return false;
569 }
570
571 bool ok = false;
572 int value = tokens[y].toInt(&ok, 16);
573 if (!ok)
574 {
575 LOG(VB_NETWORK, LOG_ERR,
576 QString("IsMACAddress(%1) = false, unable to "
577 "convert part '%2' to integer.")
578 .arg(MAC, tokens[y]));
579 return false;
580 }
581
582 if (value > 255)
583 {
584 LOG(VB_NETWORK, LOG_ERR,
585 QString("IsMACAddress(%1) = false, part #%2 "
586 "evaluates to %3 which is higher than 255.")
587 .arg(MAC).arg(y).arg(value));
588 return false;
589 }
590 }
591
592 LOG(VB_NETWORK, LOG_DEBUG, QString("IsMACAddress(%1) = true").arg(MAC));
593 return true;
594}
595
596QString FileHash(const QString& filename)
597{
598 QFile file(filename);
599 QFileInfo fileinfo(file);
600 qint64 initialsize = fileinfo.size();
601 quint64 hash = 0;
602
603 if (initialsize == 0)
604 return {"NULL"};
605
606 if (file.open(QIODevice::ReadOnly))
607 {
608 hash = initialsize;
609 }
610 else
611 {
612 LOG(VB_GENERAL, LOG_ERR,
613 "Error: Unable to open selected file, missing read permissions?");
614 return {"NULL"};
615 }
616
617 file.seek(0);
618 QDataStream stream(&file);
619 stream.setByteOrder(QDataStream::LittleEndian);
620 for (quint64 tmp = 0, i = 0; i < 65536/sizeof(tmp); i++)
621 {
622 stream >> tmp;
623 hash += tmp;
624 }
625
626 file.seek(initialsize - 65536);
627 for (quint64 tmp = 0, i = 0; i < 65536/sizeof(tmp); i++)
628 {
629 stream >> tmp;
630 hash += tmp;
631 }
632
633 file.close();
634
635 QString output = QString("%1").arg(hash, 0, 16);
636 return output;
637}
638
639bool WakeOnLAN(const QString& MAC)
640{
641 std::vector<char> msg(6, static_cast<char>(0xFF));
642 std::array<char,6> macaddr {};
643 QStringList tokens = MAC.split(':');
644
645 if (tokens.size() != 6)
646 {
647 LOG(VB_GENERAL, LOG_ERR,
648 QString( "WakeOnLan(%1): Incorrect MAC length").arg(MAC));
649 return false;
650 }
651
652 for (int y = 0; y < 6; y++)
653 {
654 bool ok = false;
655 macaddr[y] = tokens[y].toInt(&ok, 16);
656
657 if (!ok)
658 {
659 LOG(VB_GENERAL, LOG_ERR,
660 QString( "WakeOnLan(%1): Invalid MAC address").arg(MAC));
661 return false;
662 }
663 }
664
665 msg.reserve(1024);
666 for (int x = 0; x < 16; x++)
667 msg.insert(msg.end(), macaddr.cbegin(), macaddr.cend());
668
669 LOG(VB_NETWORK, LOG_INFO,
670 QString("WakeOnLan(): Sending WOL packet to %1").arg(MAC));
671
672 QUdpSocket udp_socket;
673 qlonglong msglen = msg.size();
674 return udp_socket.writeDatagram(
675 msg.data(), msglen, QHostAddress::Broadcast, 32767) == msglen;
676}
677
678// Wake up either by command or by MAC address
679// return true = success
680bool MythWakeup(const QString &wakeUpCommand, uint flags, std::chrono::seconds timeout)
681{
682 if (!IsMACAddress(wakeUpCommand))
683 return myth_system(wakeUpCommand, flags, timeout) == 0U;
684
685 return WakeOnLAN(wakeUpCommand);
686}
687
689{
690#ifdef Q_OS_WINDOWS
691 return false;
692#else
693
694#ifdef Q_OS_BSD4
695 const char *command = "ps -ax | grep -i pulseaudio | grep -v grep > /dev/null";
696#else
697 const char *command = "ps ch -C pulseaudio -o pid > /dev/null";
698#endif
699 // Do NOT use kMSProcessEvents here, it will cause deadlock
700 uint res = myth_system(command, kMSDontBlockInputDevs |
702 return (res == GENERIC_EXIT_OK);
703#endif // Q_OS_WINDOWS
704}
705
706bool myth_nice(int val)
707{
708 errno = 0;
709 int ret = nice(val);
710
711 if ((-1 == ret) && (0 != errno) && (val >= 0))
712 {
713 LOG(VB_GENERAL, LOG_ERR, "Failed to nice process" + ENO);
714 return false;
715 }
716
717 return true;
718}
719
720void myth_yield(void)
721{
722#ifdef _POSIX_PRIORITY_SCHEDULING
723 if (sched_yield()<0)
724 std::this_thread::sleep_for(5ms);
725#else
726 std::this_thread::sleep_for(5ms);
727#endif
728}
729
747#if defined(Q_OS_LINUX) && ( defined(Q_PROCESSOR_X86) || defined(Q_PROCESSOR_POWER) || \
748 defined(Q_PROCESSOR_IA64) )
749
750#include <cstdio>
751#include <getopt.h>
752#include <sys/ptrace.h>
753#include <sys/syscall.h>
754#if __has_include(<linux/ioprio.h>)
755// Starting with kernel 6.5.0, the following include uses the C++
756// reserved keyword "class" as a variable name. Fortunately we can
757// redefine it without any ill effects.
758#define class class2
759#include <linux/ioprio.h>
760#undef class
761#else
762static constexpr int8_t IOPRIO_BITS { 16 };
763static constexpr int8_t IOPRIO_CLASS_SHIFT { 13 };
764static constexpr int IOPRIO_PRIO_MASK { (1UL << IOPRIO_CLASS_SHIFT) - 1 };
765static constexpr int IOPRIO_PRIO_CLASS(int mask)
766 { return mask >> IOPRIO_CLASS_SHIFT; };
767static constexpr int IOPRIO_PRIO_DATA(int mask)
768 { return mask & IOPRIO_PRIO_MASK; };
769static constexpr int IOPRIO_PRIO_VALUE(int pclass, int data)
770 { return (pclass << IOPRIO_CLASS_SHIFT) | data; };
771
772enum { IOPRIO_CLASS_NONE,IOPRIO_CLASS_RT,IOPRIO_CLASS_BE,IOPRIO_CLASS_IDLE, };
773enum { IOPRIO_WHO_PROCESS = 1, IOPRIO_WHO_PGRP, IOPRIO_WHO_USER, };
774#endif // has_include(<linux/ioprio.h>)
775
776bool myth_ioprio(int val)
777{
778 int new_ioclass {IOPRIO_CLASS_BE};
779 if (val < 0)
780 new_ioclass = IOPRIO_CLASS_RT;
781 else if (val > 7)
782 new_ioclass = IOPRIO_CLASS_IDLE;
783 int new_iodata = (new_ioclass == IOPRIO_CLASS_BE) ? val : 0;
784 int new_ioprio = IOPRIO_PRIO_VALUE(new_ioclass, new_iodata);
785
786 int pid = getpid();
787 int old_ioprio = syscall(SYS_ioprio_get, IOPRIO_WHO_PROCESS, pid);
788 if (old_ioprio == new_ioprio)
789 return true;
790
791 int ret = syscall(SYS_ioprio_set, IOPRIO_WHO_PROCESS, pid, new_ioprio);
792
793 if (-1 == ret && EPERM == errno && IOPRIO_CLASS_BE != new_ioclass)
794 {
795 new_iodata = (new_ioclass == IOPRIO_CLASS_RT) ? 0 : 7;
796 new_ioprio = IOPRIO_PRIO_VALUE(IOPRIO_CLASS_BE, new_iodata);
797 ret = syscall(SYS_ioprio_set, IOPRIO_WHO_PROCESS, pid, new_ioprio);
798 }
799
800 return 0 == ret;
801}
802
803#else
804
805bool myth_ioprio(int /*val*/) { return true; }
806
807#endif
808
809bool MythRemoveDirectory(QDir &aDir)
810{
811 if (!aDir.exists())//QDir::NoDotAndDotDot
812 return false;
813
814 QFileInfoList entries = aDir.entryInfoList(QDir::NoDotAndDotDot |
815 QDir::Dirs | QDir::Files);
816 int count = entries.size();
817 bool has_err = false;
818
819 for (int idx = 0; idx < count && !has_err; idx++)
820 {
821 const QFileInfo& entryInfo = entries[idx];
822 QString path = entryInfo.absoluteFilePath();
823 if (entryInfo.isDir())
824 {
825 QDir dir(path);
826 has_err = MythRemoveDirectory(dir);
827 }
828 else
829 {
830 QFile file(path);
831 if (!file.remove())
832 has_err = true;
833 }
834 }
835
836 if (!has_err && !aDir.rmdir(aDir.absolutePath()))
837 has_err = true;
838
839 return has_err;
840}
841
853void setHttpProxy(void)
854{
855 QString LOC = "setHttpProxy() - ";
856
857 // Set http proxy for the application if specified in environment variable
858 QString var(qEnvironmentVariable("http_proxy"));
859 if (var.isEmpty())
860 var = qEnvironmentVariable("HTTP_PROXY"); // Sadly, some OS envs are case sensitive
861 if (!var.isEmpty())
862 {
863 if (!var.startsWith("http://")) // i.e. just a host name
864 var.prepend("http://");
865
866 QUrl url = QUrl(var, QUrl::TolerantMode);
867 QString host = url.host();
868 int port = url.port();
869
870 if (port == -1) // Parsing error
871 {
872 port = 0; // The default when creating a QNetworkProxy
873
874 if (telnet(host, 1080)) // Socks?
875 port = 1080;
876 if (telnet(host, 3128)) // Squid
877 port = 3128;
878 if (telnet(host, 8080)) // MS ISA
879 port = 8080;
880
881 LOG(VB_NETWORK, LOG_INFO, LOC +
882 QString("assuming port %1 on host %2") .arg(port).arg(host));
883 url.setPort(port);
884 }
885 else if (!ping(host, 1s))
886 {
887 LOG(VB_GENERAL, LOG_ERR, LOC +
888 QString("cannot locate host %1").arg(host) +
889 "\n\t\t\tPlease check HTTP_PROXY environment variable!");
890 }
891 else if (!telnet(host,port))
892 {
893 LOG(VB_GENERAL, LOG_ERR, LOC +
894 QString("%1:%2 - cannot connect!").arg(host).arg(port) +
895 "\n\t\t\tPlease check HTTP_PROXY environment variable!");
896 }
897
898#if 0
899 LOG(VB_NETWORK, LOG_DEBUG, LOC + QString("using http://%1:%2@%3:%4")
900 .arg(url.userName()).arg(url.password())
901 .arg(host).arg(port));
902#endif
903 QNetworkProxy p =
904 QNetworkProxy(QNetworkProxy::HttpCachingProxy,
905 host, port, url.userName(), url.password());
906 QNetworkProxy::setApplicationProxy(p);
907 return;
908 }
909
910 LOG(VB_NETWORK, LOG_DEBUG, LOC + "no HTTP_PROXY environment var.");
911
912 // Use Qt to look for user proxy settings stored by the OS or browser:
913
914 QList<QNetworkProxy> proxies;
915 QNetworkProxyQuery query(QUrl("http://www.mythtv.org"));
916
917 proxies = QNetworkProxyFactory::systemProxyForQuery(query);
918
919 for (const auto& p : std::as_const(proxies))
920 {
921 QString host = p.hostName();
922 int port = p.port();
923
924 if (p.type() == QNetworkProxy::NoProxy)
925 continue;
926
927 if (!telnet(host, port))
928 {
929 LOG(VB_NETWORK, LOG_ERR, LOC +
930 "failed to contact proxy host " + host);
931 continue;
932 }
933
934 LOG(VB_NETWORK, LOG_INFO, LOC + QString("using proxy host %1:%2")
935 .arg(host).arg(port));
936 QNetworkProxy::setApplicationProxy(p);
937
938 // Allow sub-commands to use this proxy
939 // via myth_system(command), by setting HTTP_PROXY
940 QString url;
941
942 if (!p.user().isEmpty())
943 {
944 url = "http://%1:%2@%3:%4",
945 url = url.arg(p.user(), p.password());
946 }
947 else
948 {
949 url = "http://%1:%2";
950 }
951
952 url = url.arg(p.hostName()).arg(p.port());
953 qputenv("HTTP_PROXY", url.toLocal8Bit().constData());
954 if (!qEnvironmentVariableIsSet("http_proxy"))
955 {
956 qputenv("http_proxy", url.toLocal8Bit().constData());
957 }
958
959 return;
960 }
961
962 LOG(VB_NETWORK, LOG_ERR, LOC + "failed to find a network proxy");
963}
964
965/* vim: set expandtab tabstop=4 shiftwidth=4: */
static QString resolveAddress(const QString &host, ResolveType type=ResolveAny, bool keepscope=false)
if host is an IP address, it will be returned or resolved otherwise.
bool SendReceiveStringList(QStringList &strlist, bool quickTimeout=false, bool block=true)
Send a message to the backend and wait for a response.
Class for communcating between myth backends and frontends.
Definition: mythsocket.h:26
#define getloadavg(x, y)
Definition: compat.h:127
unsigned int uint
Definition: compat.h:60
#define nice(x)
Definition: compat.h:63
#define close
Definition: compat.h:28
@ GENERIC_EXIT_OK
Exited with no error.
Definition: exitcodes.h:13
#define LOC
Definition: mythcontext.cpp:72
MythCoreContext * gCoreContext
This global variable contains the MythCoreContext instance for the app.
#define ENO
This can be appended to the LOG args with "+".
Definition: mythlogging.h:74
#define LOG(_MASK_, _LEVEL_, _QSTRING_)
Definition: mythlogging.h:39
bool RemoteGetUptime(std::chrono::seconds &uptime)
bool getMemStats(int &totalMB, int &freeMB, int &totalVM, int &freeVM)
Returns memory statistics in megabytes.
loadArray getLoadAvgs(void)
Returns the system load averages.
bool RemoteGetLoad(loadArray &load)
bool MythWakeup(const QString &wakeUpCommand, uint flags, std::chrono::seconds timeout)
bool MythRemoveDirectory(QDir &aDir)
bool IsMACAddress(const QString &MAC)
int intResponse(const QString &query, int def)
In an interactive shell, prompt the user to input a number.
bool getUptime(std::chrono::seconds &uptime)
Returns uptime statistics.
QString getResponse(const QString &query, const QString &def)
In an interactive shell, prompt the user to input a string.
bool IsPulseAudioRunning(void)
Is A/V Sync destruction daemon is running on this host?
QString getSymlinkTarget(const QString &start_file, QStringList *intermediaries, unsigned maxLinks)
void myth_yield(void)
void setHttpProxy(void)
Get network proxy settings from OS, and use for [Q]Http[Comms].
bool WakeOnLAN(const QString &MAC)
QString FileHash(const QString &filename)
bool telnet(const QString &host, int port)
Can we talk to port on host?
bool RemoteGetMemStats(int &totalMB, int &freeMB, int &totalVM, int &freeVM)
bool ping(const QString &host, std::chrono::milliseconds timeout)
Can we ping host within timeout seconds?
bool myth_nice(int val)
bool myth_ioprio(int)
Allows setting the I/O priority of the current process/thread.
bool makeFileAccessible(const QString &filename)
QString createTempFile(QString name_template, bool dir)
std::array< double, 3 > loadArray
Definition: mythmiscutil.h:26
@ kMSDontBlockInputDevs
avoid blocking LIRC & Joystick Menu
Definition: mythsystem.h:36
@ kMSProcessEvents
process events while waiting
Definition: mythsystem.h:39
@ kMSDontDisableDrawing
avoid disabling UI drawing
Definition: mythsystem.h:37
uint myth_system(const QString &command, uint flags, std::chrono::seconds timeout)
MBASE_PUBLIC long long copy(QFile &dst, QFile &src, uint block_size=0)
Copies src file to dst file.
string temppath
Definition: mythburn.py:159
#define output