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