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