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