Add missing native BSD support for Beast

This commit is contained in:
Vinnie Falco
2013-06-26 07:56:00 -07:00
parent dd07fb880c
commit f61c33538b
12 changed files with 1330 additions and 11 deletions

View File

@@ -52,6 +52,14 @@ env.ParseConfig('pkg-config --cflags --libs openssl')
# Use protobuf
env.ParseConfig('pkg-config --cflags --libs protobuf')
# Beast uses kvm on FreeBSD
if FreeBSD:
env.Append (
LIBS = [
'kvm'
]
)
# The required version of boost is documented in the README file.
#
# We whitelist platforms where the non -mt version is linked with pthreads.
@@ -59,6 +67,7 @@ env.ParseConfig('pkg-config --cflags --libs protobuf')
# If a threading library is included the platform can be whitelisted.
#
# FreeBSD and Ubuntu non-mt libs do link with pthreads.
if FreeBSD or Ubuntu:
env.Append(
LIBS = [

View File

@@ -419,6 +419,22 @@
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
</ClCompile>
<ClCompile Include="..\..\modules\beast_core\native\beast_bsd_Files.cpp">
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
</ClCompile>
<ClCompile Include="..\..\modules\beast_core\native\beast_bsd_Network.cpp">
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
</ClCompile>
<ClCompile Include="..\..\modules\beast_core\native\beast_bsd_SystemStats.cpp">
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
</ClCompile>
<ClCompile Include="..\..\modules\beast_core\native\beast_bsd_Threads.cpp">
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
</ClCompile>
<ClCompile Include="..\..\modules\beast_core\native\beast_linux_Files.cpp">
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>

View File

@@ -952,5 +952,17 @@
<ClCompile Include="..\..\modules\beast_basics\threads\beast_ThreadWithCallQueue.cpp">
<Filter>beast_basics\threads</Filter>
</ClCompile>
<ClCompile Include="..\..\modules\beast_core\native\beast_bsd_SystemStats.cpp">
<Filter>beast_core\native</Filter>
</ClCompile>
<ClCompile Include="..\..\modules\beast_core\native\beast_bsd_Files.cpp">
<Filter>beast_core\native</Filter>
</ClCompile>
<ClCompile Include="..\..\modules\beast_core\native\beast_bsd_Network.cpp">
<Filter>beast_core\native</Filter>
</ClCompile>
<ClCompile Include="..\..\modules\beast_core\native\beast_bsd_Threads.cpp">
<Filter>beast_core\native</Filter>
</ClCompile>
</ItemGroup>
</Project>

View File

@@ -201,6 +201,13 @@ namespace beast
#include "native/beast_linux_SystemStats.cpp"
#include "native/beast_linux_Threads.cpp"
//==============================================================================
#elif BEAST_BSD
#include "native/beast_bsd_Files.cpp"
#include "native/beast_bsd_Network.cpp"
#include "native/beast_bsd_SystemStats.cpp"
#include "native/beast_bsd_Threads.cpp"
//==============================================================================
#elif BEAST_ANDROID
#include "native/beast_android_Files.cpp"

View File

@@ -188,8 +188,17 @@
#if BEAST_BSD
#include <dirent.h>
#include <kvm.h>
#include <langinfo.h>
#include <sys/cdefs.h>
#include <sys/param.h>
#include <sys/mount.h>
#include <sys/types.h>
#include <sys/sysctl.h>
// This has to be in the global namespace
extern char** environ;
#else
#include <sys/dir.h>
#include <sys/vfs.h>

View File

@@ -0,0 +1,373 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
Portions of this file are from JUCE.
Copyright (c) 2013 - Raw Material Software Ltd.
Please visit http://www.juce.com
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
enum
{
U_ISOFS_SUPER_MAGIC = 0x9660, // linux/iso_fs.h
U_MSDOS_SUPER_MAGIC = 0x4d44, // linux/msdos_fs.h
U_NFS_SUPER_MAGIC = 0x6969, // linux/nfs_fs.h
U_SMB_SUPER_MAGIC = 0x517B // linux/smb_fs.h
};
//==============================================================================
bool File::copyInternal (const File& dest) const
{
FileInputStream in (*this);
if (dest.deleteFile())
{
{
FileOutputStream out (dest);
if (out.failedToOpen())
return false;
if (out.writeFromInputStream (in, -1) == getSize())
return true;
}
dest.deleteFile();
}
return false;
}
void File::findFileSystemRoots (Array<File>& destArray)
{
destArray.add (File ("/"));
}
//==============================================================================
bool File::isOnCDRomDrive() const
{
struct statfs buf;
return statfs (getFullPathName().toUTF8(), &buf) == 0
&& buf.f_type == (short) U_ISOFS_SUPER_MAGIC;
}
bool File::isOnHardDisk() const
{
struct statfs buf;
if (statfs (getFullPathName().toUTF8(), &buf) == 0)
{
switch (buf.f_type)
{
case U_ISOFS_SUPER_MAGIC: // CD-ROM
case U_MSDOS_SUPER_MAGIC: // Probably floppy (but could be mounted FAT filesystem)
case U_NFS_SUPER_MAGIC: // Network NFS
case U_SMB_SUPER_MAGIC: // Network Samba
return false;
default:
// Assume anything else is a hard-disk (but note it could
// be a RAM disk. There isn't a good way of determining
// this for sure)
return true;
}
}
// Assume so if this fails for some reason
return true;
}
bool File::isOnRemovableDrive() const
{
bassertfalse; // xxx not implemented for linux!
return false;
}
bool File::isHidden() const
{
return getFileName().startsWithChar ('.');
}
//==============================================================================
namespace
{
File beast_readlink (const String& file, const File& defaultFile)
{
const size_t size = 8192;
HeapBlock<char> buffer;
buffer.malloc (size + 4);
const size_t numBytes = readlink (file.toUTF8(), buffer, size);
if (numBytes > 0 && numBytes <= size)
return File (file).getSiblingFile (String::fromUTF8 (buffer, (int) numBytes));
return defaultFile;
}
}
File File::getLinkedTarget() const
{
return beast_readlink (getFullPathName().toUTF8(), *this);
}
//==============================================================================
static File resolveXDGFolder (const char* const type, const char* const fallbackFolder)
{
StringArray confLines;
File ("~/.config/user-dirs.dirs").readLines (confLines);
for (int i = 0; i < confLines.size(); ++i)
{
const String line (confLines[i].trimStart());
if (line.startsWith (type))
{
// eg. resolve XDG_MUSIC_DIR="$HOME/Music" to /home/user/Music
const File f (line.replace ("$HOME", File ("~").getFullPathName())
.fromFirstOccurrenceOf ("=", false, false)
.trim().unquoted());
if (f.isDirectory())
return f;
}
}
return File (fallbackFolder);
}
const char* const* beast_argv = nullptr;
int beast_argc = 0;
File File::getSpecialLocation (const SpecialLocationType type)
{
switch (type)
{
case userHomeDirectory:
{
const char* homeDir = getenv ("HOME");
if (homeDir == nullptr)
{
struct passwd* const pw = getpwuid (getuid());
if (pw != nullptr)
homeDir = pw->pw_dir;
}
return File (CharPointer_UTF8 (homeDir));
}
case userDocumentsDirectory: return resolveXDGFolder ("XDG_DOCUMENTS_DIR", "~");
case userMusicDirectory: return resolveXDGFolder ("XDG_MUSIC_DIR", "~");
case userMoviesDirectory: return resolveXDGFolder ("XDG_VIDEOS_DIR", "~");
case userPicturesDirectory: return resolveXDGFolder ("XDG_PICTURES_DIR", "~");
case userDesktopDirectory: return resolveXDGFolder ("XDG_DESKTOP_DIR", "~/Desktop");
case userApplicationDataDirectory: return File ("~");
case commonApplicationDataDirectory: return File ("/var");
case globalApplicationsDirectory: return File ("/usr");
case tempDirectory:
{
File tmp ("/var/tmp");
if (! tmp.isDirectory())
{
tmp = "/tmp";
if (! tmp.isDirectory())
tmp = File::getCurrentWorkingDirectory();
}
return tmp;
}
case invokedExecutableFile:
if (beast_argv != nullptr && beast_argc > 0)
return File (CharPointer_UTF8 (beast_argv[0]));
// deliberate fall-through...
case currentExecutableFile:
case currentApplicationFile:
return beast_getExecutableFile();
case hostApplicationPath:
return beast_readlink ("/proc/self/exe", beast_getExecutableFile());
default:
bassertfalse; // unknown type?
break;
}
return File::nonexistent;
}
//==============================================================================
String File::getVersion() const
{
return String::empty; // xxx not yet implemented
}
//==============================================================================
bool File::moveToTrash() const
{
if (! exists())
return true;
File trashCan ("~/.Trash");
if (! trashCan.isDirectory())
trashCan = "~/.local/share/Trash/files";
if (! trashCan.isDirectory())
return false;
return moveFileTo (trashCan.getNonexistentChildFile (getFileNameWithoutExtension(),
getFileExtension()));
}
//==============================================================================
class DirectoryIterator::NativeIterator::Pimpl
{
public:
Pimpl (const File& directory, const String& wildCard_)
: parentDir (File::addTrailingSeparator (directory.getFullPathName())),
wildCard (wildCard_),
dir (opendir (directory.getFullPathName().toUTF8()))
{
}
~Pimpl()
{
if (dir != nullptr)
closedir (dir);
}
bool next (String& filenameFound,
bool* const isDir, bool* const isHidden, int64* const fileSize,
Time* const modTime, Time* const creationTime, bool* const isReadOnly)
{
if (dir != nullptr)
{
const char* wildcardUTF8 = nullptr;
for (;;)
{
struct dirent* const de = readdir (dir);
if (de == nullptr)
break;
if (wildcardUTF8 == nullptr)
wildcardUTF8 = wildCard.toUTF8();
if (fnmatch (wildcardUTF8, de->d_name, FNM_CASEFOLD) == 0)
{
filenameFound = CharPointer_UTF8 (de->d_name);
updateStatInfoForFile (parentDir + filenameFound, isDir, fileSize, modTime, creationTime, isReadOnly);
if (isHidden != nullptr)
*isHidden = filenameFound.startsWithChar ('.');
return true;
}
}
}
return false;
}
private:
String parentDir, wildCard;
DIR* dir;
BEAST_DECLARE_NON_COPYABLE (Pimpl)
};
DirectoryIterator::NativeIterator::NativeIterator (const File& directory, const String& wildCard)
: pimpl (new DirectoryIterator::NativeIterator::Pimpl (directory, wildCard))
{
}
DirectoryIterator::NativeIterator::~NativeIterator()
{
}
bool DirectoryIterator::NativeIterator::next (String& filenameFound,
bool* const isDir, bool* const isHidden, int64* const fileSize,
Time* const modTime, Time* const creationTime, bool* const isReadOnly)
{
return pimpl->next (filenameFound, isDir, isHidden, fileSize, modTime, creationTime, isReadOnly);
}
//==============================================================================
static bool isFileExecutable (const String& filename)
{
beast_statStruct info;
return beast_stat (filename, info)
&& S_ISREG (info.st_mode)
&& access (filename.toUTF8(), X_OK) == 0;
}
bool Process::openDocument (const String& fileName, const String& parameters)
{
String cmdString (fileName.replace (" ", "\\ ",false));
cmdString << " " << parameters;
if (URL::isProbablyAWebsiteURL (fileName)
|| cmdString.startsWithIgnoreCase ("file:")
|| URL::isProbablyAnEmailAddress (fileName)
|| File::createFileWithoutCheckingPath (fileName).isDirectory()
|| ! isFileExecutable (fileName))
{
// create a command that tries to launch a bunch of likely browsers
const char* const browserNames[] = { "xdg-open", "/etc/alternatives/x-www-browser", "firefox", "mozilla",
"google-chrome", "chromium-browser", "opera", "konqueror" };
StringArray cmdLines;
for (int i = 0; i < numElementsInArray (browserNames); ++i)
cmdLines.add (String (browserNames[i]) + " " + cmdString.trim().quoted());
cmdString = cmdLines.joinIntoString (" || ");
}
const char* const argv[4] = { "/bin/sh", "-c", cmdString.toUTF8(), 0 };
const int cpid = fork();
if (cpid == 0)
{
setsid();
// Child process
execve (argv[0], (char**) argv, environ);
exit (0);
}
return cpid >= 0;
}
void File::revealToUser() const
{
if (isDirectory())
startAsProcess();
else if (getParentDirectory().exists())
getParentDirectory().startAsProcess();
}

View File

@@ -0,0 +1,461 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
Portions of this file are from JUCE.
Copyright (c) 2013 - Raw Material Software Ltd.
Please visit http://www.juce.com
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
void MACAddress::findAllAddresses (Array<MACAddress>& result)
{
#if 1
bassertfalse; // VFALCO TODO Implement for FreeBSD
#else
const int s = socket (AF_INET, SOCK_DGRAM, 0);
if (s != -1)
{
char buf [1024];
struct ifconf ifc;
ifc.ifc_len = sizeof (buf);
ifc.ifc_buf = buf;
ioctl (s, SIOCGIFCONF, &ifc);
for (unsigned int i = 0; i < ifc.ifc_len / sizeof (struct ifreq); ++i)
{
struct ifreq ifr;
strcpy (ifr.ifr_name, ifc.ifc_req[i].ifr_name);
if (ioctl (s, SIOCGIFFLAGS, &ifr) == 0
&& (ifr.ifr_flags & IFF_LOOPBACK) == 0
&& ioctl (s, SIOCGIFHWADDR, &ifr) == 0)
{
result.addIfNotAlreadyThere (MACAddress ((const uint8*) ifr.ifr_hwaddr.sa_data));
}
}
close (s);
}
#endif
}
bool Process::openEmailWithAttachments (const String& /* targetEmailAddress */,
const String& /* emailSubject */,
const String& /* bodyText */,
const StringArray& /* filesToAttach */)
{
bassertfalse; // xxx todo
return false;
}
//==============================================================================
class WebInputStream : public InputStream
{
public:
WebInputStream (const String& address_, bool isPost_, const MemoryBlock& postData_,
URL::OpenStreamProgressCallback* progressCallback, void* progressCallbackContext,
const String& headers_, int timeOutMs_, StringPairArray* responseHeaders)
: socketHandle (-1), levelsOfRedirection (0),
address (address_), headers (headers_), postData (postData_), position (0),
finished (false), isPost (isPost_), timeOutMs (timeOutMs_)
{
createConnection (progressCallback, progressCallbackContext);
if (responseHeaders != nullptr && ! isError())
{
for (int i = 0; i < headerLines.size(); ++i)
{
const String& headersEntry = headerLines[i];
const String key (headersEntry.upToFirstOccurrenceOf (": ", false, false));
const String value (headersEntry.fromFirstOccurrenceOf (": ", false, false));
const String previousValue ((*responseHeaders) [key]);
responseHeaders->set (key, previousValue.isEmpty() ? value : (previousValue + "," + value));
}
}
}
~WebInputStream()
{
closeSocket();
}
//==============================================================================
bool isError() const { return socketHandle < 0; }
bool isExhausted() { return finished; }
int64 getPosition() { return position; }
int64 getTotalLength()
{
//xxx to do
return -1;
}
int read (void* buffer, int bytesToRead)
{
if (finished || isError())
return 0;
fd_set readbits;
FD_ZERO (&readbits);
FD_SET (socketHandle, &readbits);
struct timeval tv;
tv.tv_sec = bmax (1, timeOutMs / 1000);
tv.tv_usec = 0;
if (select (socketHandle + 1, &readbits, 0, 0, &tv) <= 0)
return 0; // (timeout)
const int bytesRead = bmax (0, (int) recv (socketHandle, buffer, bytesToRead, MSG_WAITALL));
if (bytesRead == 0)
finished = true;
position += bytesRead;
return bytesRead;
}
bool setPosition (int64 wantedPos)
{
if (isError())
return false;
if (wantedPos != position)
{
finished = false;
if (wantedPos < position)
{
closeSocket();
position = 0;
createConnection (0, 0);
}
skipNextBytes (wantedPos - position);
}
return true;
}
//==============================================================================
private:
int socketHandle, levelsOfRedirection;
StringArray headerLines;
String address, headers;
MemoryBlock postData;
int64 position;
bool finished;
const bool isPost;
const int timeOutMs;
void closeSocket()
{
if (socketHandle >= 0)
close (socketHandle);
socketHandle = -1;
levelsOfRedirection = 0;
}
void createConnection (URL::OpenStreamProgressCallback* progressCallback, void* progressCallbackContext)
{
closeSocket();
uint32 timeOutTime = Time::getMillisecondCounter();
if (timeOutMs == 0)
timeOutTime += 60000;
else if (timeOutMs < 0)
timeOutTime = 0xffffffff;
else
timeOutTime += timeOutMs;
String hostName, hostPath;
int hostPort;
if (! decomposeURL (address, hostName, hostPath, hostPort))
return;
String serverName, proxyName, proxyPath;
int proxyPort = 0;
int port = 0;
const String proxyURL (getenv ("http_proxy"));
if (proxyURL.startsWithIgnoreCase ("http://"))
{
if (! decomposeURL (proxyURL, proxyName, proxyPath, proxyPort))
return;
serverName = proxyName;
port = proxyPort;
}
else
{
serverName = hostName;
port = hostPort;
}
struct addrinfo hints;
zerostruct (hints);
hints.ai_family = AF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;
hints.ai_flags = AI_NUMERICSERV;
struct addrinfo* result = nullptr;
if (getaddrinfo (serverName.toUTF8(), String (port).toUTF8(), &hints, &result) != 0 || result == 0)
return;
socketHandle = socket (result->ai_family, result->ai_socktype, 0);
if (socketHandle == -1)
{
freeaddrinfo (result);
return;
}
int receiveBufferSize = 16384;
setsockopt (socketHandle, SOL_SOCKET, SO_RCVBUF, (char*) &receiveBufferSize, sizeof (receiveBufferSize));
setsockopt (socketHandle, SOL_SOCKET, SO_KEEPALIVE, 0, 0);
#if BEAST_MAC
setsockopt (socketHandle, SOL_SOCKET, SO_NOSIGPIPE, 0, 0);
#endif
if (connect (socketHandle, result->ai_addr, result->ai_addrlen) == -1)
{
closeSocket();
freeaddrinfo (result);
return;
}
freeaddrinfo (result);
{
const MemoryBlock requestHeader (createRequestHeader (hostName, hostPort, proxyName, proxyPort,
hostPath, address, headers, postData, isPost));
if (! sendHeader (socketHandle, requestHeader, timeOutTime, progressCallback, progressCallbackContext))
{
closeSocket();
return;
}
}
String responseHeader (readResponse (socketHandle, timeOutTime));
if (responseHeader.isNotEmpty())
{
headerLines = StringArray::fromLines (responseHeader);
const int statusCode = responseHeader.fromFirstOccurrenceOf (" ", false, false)
.substring (0, 3).getIntValue();
//int contentLength = findHeaderItem (lines, "Content-Length:").getIntValue();
//bool isChunked = findHeaderItem (lines, "Transfer-Encoding:").equalsIgnoreCase ("chunked");
String location (findHeaderItem (headerLines, "Location:"));
if (statusCode >= 300 && statusCode < 400 && location.isNotEmpty())
{
if (! location.startsWithIgnoreCase ("http://"))
location = "http://" + location;
if (++levelsOfRedirection <= 3)
{
address = location;
createConnection (progressCallback, progressCallbackContext);
return;
}
}
else
{
levelsOfRedirection = 0;
return;
}
}
closeSocket();
}
//==============================================================================
static String readResponse (const int socketHandle, const uint32 timeOutTime)
{
int bytesRead = 0, numConsecutiveLFs = 0;
MemoryBlock buffer (1024, true);
while (numConsecutiveLFs < 2 && bytesRead < 32768
&& Time::getMillisecondCounter() <= timeOutTime)
{
fd_set readbits;
FD_ZERO (&readbits);
FD_SET (socketHandle, &readbits);
struct timeval tv;
tv.tv_sec = bmax (1, (int) (timeOutTime - Time::getMillisecondCounter()) / 1000);
tv.tv_usec = 0;
if (select (socketHandle + 1, &readbits, 0, 0, &tv) <= 0)
return String::empty; // (timeout)
buffer.ensureSize (bytesRead + 8, true);
char* const dest = (char*) buffer.getData() + bytesRead;
if (recv (socketHandle, dest, 1, 0) == -1)
return String::empty;
const char lastByte = *dest;
++bytesRead;
if (lastByte == '\n')
++numConsecutiveLFs;
else if (lastByte != '\r')
numConsecutiveLFs = 0;
}
const String header (CharPointer_UTF8 ((const char*) buffer.getData()));
if (header.startsWithIgnoreCase ("HTTP/"))
return header.trimEnd();
return String::empty;
}
static void writeValueIfNotPresent (MemoryOutputStream& dest, const String& headers, const String& key, const String& value)
{
if (! headers.containsIgnoreCase (key))
dest << "\r\n" << key << ' ' << value;
}
static void writeHost (MemoryOutputStream& dest, const bool isPost, const String& path, const String& host, const int port)
{
dest << (isPost ? "POST " : "GET ") << path << " HTTP/1.0\r\nHost: " << host;
if (port > 0)
dest << ':' << port;
}
static MemoryBlock createRequestHeader (const String& hostName, const int hostPort,
const String& proxyName, const int proxyPort,
const String& hostPath, const String& originalURL,
const String& userHeaders, const MemoryBlock& postData,
const bool isPost)
{
MemoryOutputStream header;
if (proxyName.isEmpty())
writeHost (header, isPost, hostPath, hostName, hostPort);
else
writeHost (header, isPost, originalURL, proxyName, proxyPort);
writeValueIfNotPresent (header, userHeaders, "User-Agent:", "BEAST/" BEAST_STRINGIFY(BEAST_MAJOR_VERSION)
"." BEAST_STRINGIFY(BEAST_MINOR_VERSION)
"." BEAST_STRINGIFY(BEAST_BUILDNUMBER));
writeValueIfNotPresent (header, userHeaders, "Connection:", "Close");
if (isPost)
writeValueIfNotPresent (header, userHeaders, "Content-Length:", String ((int) postData.getSize()));
header << "\r\n" << userHeaders
<< "\r\n" << postData;
return header.getMemoryBlock();
}
static bool sendHeader (int socketHandle, const MemoryBlock& requestHeader, const uint32 timeOutTime,
URL::OpenStreamProgressCallback* progressCallback, void* progressCallbackContext)
{
size_t totalHeaderSent = 0;
while (totalHeaderSent < requestHeader.getSize())
{
if (Time::getMillisecondCounter() > timeOutTime)
return false;
const int numToSend = bmin (1024, (int) (requestHeader.getSize() - totalHeaderSent));
if (send (socketHandle, static_cast <const char*> (requestHeader.getData()) + totalHeaderSent, numToSend, 0) != numToSend)
return false;
totalHeaderSent += numToSend;
if (progressCallback != nullptr && ! progressCallback (progressCallbackContext, totalHeaderSent, requestHeader.getSize()))
return false;
}
return true;
}
static bool decomposeURL (const String& url, String& host, String& path, int& port)
{
if (! url.startsWithIgnoreCase ("http://"))
return false;
const int nextSlash = url.indexOfChar (7, '/');
int nextColon = url.indexOfChar (7, ':');
if (nextColon > nextSlash && nextSlash > 0)
nextColon = -1;
if (nextColon >= 0)
{
host = url.substring (7, nextColon);
if (nextSlash >= 0)
port = url.substring (nextColon + 1, nextSlash).getIntValue();
else
port = url.substring (nextColon + 1).getIntValue();
}
else
{
port = 80;
if (nextSlash >= 0)
host = url.substring (7, nextSlash);
else
host = url.substring (7);
}
if (nextSlash >= 0)
path = url.substring (nextSlash);
else
path = "/";
return true;
}
static String findHeaderItem (const StringArray& lines, const String& itemName)
{
for (int i = 0; i < lines.size(); ++i)
if (lines[i].startsWithIgnoreCase (itemName))
return lines[i].substring (itemName.length()).trim();
return String::empty;
}
BEAST_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (WebInputStream)
};
InputStream* URL::createNativeStream (const String& address, bool isPost, const MemoryBlock& postData,
OpenStreamProgressCallback* progressCallback, void* progressCallbackContext,
const String& headers, const int timeOutMs, StringPairArray* responseHeaders)
{
ScopedPointer <WebInputStream> wi (new WebInputStream (address, isPost, postData,
progressCallback, progressCallbackContext,
headers, timeOutMs, responseHeaders));
return wi->isError() ? nullptr : wi.release();
}

View File

@@ -0,0 +1,346 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
Portions of this file are from JUCE.
Copyright (c) 2013 - Raw Material Software Ltd.
Please visit http://www.juce.com
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
// sysinfo() from sysinfo-bsd
// https://code.google.com/p/sysinfo-bsd/
/*
* Copyright (C) 2010 Kostas Petrikas, All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer
* in this position and unchanged.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. The name(s) of the author(s) may not be used to endorse or promote
* products derived from this software without specific prior written
* permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#define SI_LOAD_SHIFT 16
struct sysinfo {
long uptime; /* Seconds since boot */
unsigned long loads[3]; /* 1, 5, and 15 minute load averages */
unsigned long totalram; /* Total usable main memory size */
unsigned long freeram; /* Available memory size */
unsigned long sharedram; /* Amount of shared memory */
unsigned long bufferram; /* Memory used by buffers */
unsigned long totalswap; /* Total swap space size */
unsigned long freeswap; /* swap space still available */
unsigned short procs; /* Number of current processes */
unsigned short pad; /* leaving this for linux compatability */
unsigned long totalhigh; /* Total high memory size */
unsigned long freehigh; /* Available high memory size */
unsigned int mem_unit; /* Memory unit size in bytes */
char _f[20-2*sizeof(long)-sizeof(int)]; /* leaving this for linux compatability */
};
#define NLOADS 3
#define UNIT_S 1024 /*Kb*/
#define R_IGNORE -1
/*the macros*/
#define R_ERROR(_EC) {if(_EC > R_IGNORE)errno = _EC; return -1;}
#define GETSYSCTL(name, var) getsysctl((char*)name, &(var), sizeof(var))
#define PAGE_2_UNIT(_PAGE) (((double)_PAGE * page_s) / UNIT_S)
/*sysctl wrapper*/
static int getsysctl(char *name, void *ptr, size_t len){
size_t nlen = len;
if (sysctlbyname(name, ptr, &nlen, NULL, 0) == -1)
return -1;
if (nlen != len)
return -1;
return 0;
}
int sysinfo(struct sysinfo *info){
kvm_t *kvmh;
double load_avg[NLOADS];
int page_s = getpagesize();
if (info == NULL)
R_ERROR(EFAULT);
memset(info, 0, sizeof(struct sysinfo));
info -> mem_unit = UNIT_S;
/*kvm init*/
if ((kvmh = kvm_open(NULL, "/dev/null", "/dev/null",
O_RDONLY, "kvm_open")) == NULL)
R_ERROR(0);
/*load averages*/
if (kvm_getloadavg(kvmh, load_avg, NLOADS) == -1)
R_ERROR(0);
info -> loads[0] = (u_long)((float)load_avg[0] * USHRT_MAX);
info -> loads[1] = (u_long)((float)load_avg[1] * USHRT_MAX);
info -> loads[2] = (u_long)((float)load_avg[2] * USHRT_MAX);
/*swap space*/
struct kvm_swap k_swap;
if (kvm_getswapinfo(kvmh, &k_swap, 1, 0) == -1)
R_ERROR(0);
info -> totalswap =
(u_long)PAGE_2_UNIT(k_swap.ksw_total);
info -> freeswap = info -> totalswap -
(u_long)PAGE_2_UNIT(k_swap.ksw_used);
/*processes*/
int n_procs;
if (kvm_getprocs(kvmh, KERN_PROC_ALL, 0, &n_procs) == NULL)
R_ERROR(0);
info -> procs = (u_short)n_procs;
/*end of kvm session*/
if (kvm_close(kvmh) == -1)
R_ERROR(0);
/*uptime*/
struct timespec ts;
if (clock_gettime(CLOCK_UPTIME, &ts) == -1)
R_ERROR(R_IGNORE);
info -> uptime = (long)ts.tv_sec;
/*ram*/
int total_pages,
free_pages,
active_pages,
inactive_pages;
u_long shmmax;
if (GETSYSCTL("vm.stats.vm.v_page_count", total_pages) == -1)
R_ERROR(R_IGNORE);
if (GETSYSCTL("vm.stats.vm.v_free_count", free_pages) == -1)
R_ERROR(R_IGNORE);
if (GETSYSCTL("vm.stats.vm.v_active_count", active_pages) == -1)
R_ERROR(R_IGNORE);
if (GETSYSCTL("vm.stats.vm.v_inactive_count", inactive_pages) == -1)
R_ERROR(R_IGNORE);
if (GETSYSCTL("kern.ipc.shmmax", shmmax) == -1)
R_ERROR(R_IGNORE);
info -> totalram = (u_long)PAGE_2_UNIT(total_pages);
info -> freeram = (u_long)PAGE_2_UNIT(free_pages);
info -> bufferram = (u_long)PAGE_2_UNIT(active_pages);
info -> sharedram = shmmax / UNIT_S;
/*high mem (todo)*/
info -> totalhigh = 0; /*Does this supose to refer to HMA or reserved ram?*/
info -> freehigh = 0;
return 0;
}
//==============================================================================
void Logger::outputDebugString (const String& text)
{
std::cerr << text << std::endl;
}
//==============================================================================
SystemStats::OperatingSystemType SystemStats::getOperatingSystemType()
{
return FreeBSD;
}
String SystemStats::getOperatingSystemName()
{
return "FreeBSD";
}
bool SystemStats::isOperatingSystem64Bit()
{
#if BEAST_64BIT
return true;
#else
//xxx not sure how to find this out?..
return false;
#endif
}
//==============================================================================
namespace BSDStatsHelpers
{
String getCpuInfo (const char* const key)
{
StringArray lines;
File ("/proc/cpuinfo").readLines (lines);
for (int i = lines.size(); --i >= 0;) // (NB - it's important that this runs in reverse order)
if (lines[i].startsWithIgnoreCase (key))
return lines[i].fromFirstOccurrenceOf (":", false, false).trim();
return String::empty;
}
}
String SystemStats::getCpuVendor()
{
return BSDStatsHelpers::getCpuInfo ("vendor_id");
}
int SystemStats::getCpuSpeedInMegaherz()
{
return roundToInt (BSDStatsHelpers::getCpuInfo ("cpu MHz").getFloatValue());
}
int SystemStats::getMemorySizeInMegabytes()
{
struct sysinfo sysi;
if (sysinfo (&sysi) == 0)
return (sysi.totalram * sysi.mem_unit / (1024 * 1024));
return 0;
}
int SystemStats::getPageSize()
{
return sysconf (_SC_PAGESIZE);
}
//==============================================================================
String SystemStats::getLogonName()
{
const char* user = getenv ("USER");
if (user == nullptr)
{
struct passwd* const pw = getpwuid (getuid());
if (pw != nullptr)
user = pw->pw_name;
}
return CharPointer_UTF8 (user);
}
String SystemStats::getFullUserName()
{
return getLogonName();
}
String SystemStats::getComputerName()
{
char name [256] = { 0 };
if (gethostname (name, sizeof (name) - 1) == 0)
return name;
return String::empty;
}
String getLocaleValue (nl_item key)
{
const char* oldLocale = ::setlocale (LC_ALL, "");
return String (const_cast <const char*> (nl_langinfo (key)));
::setlocale (LC_ALL, oldLocale);
}
String SystemStats::getUserLanguage()
{
return "Uknown user language";
}
String SystemStats::getUserRegion()
{
return "Unknown user region";
}
String SystemStats::getDisplayLanguage()
{
return getUserLanguage();
}
//==============================================================================
SystemStats::CPUFlags::CPUFlags()
{
const String flags (BSDStatsHelpers::getCpuInfo ("flags"));
hasMMX = flags.contains ("mmx");
hasSSE = flags.contains ("sse");
hasSSE2 = flags.contains ("sse2");
has3DNow = flags.contains ("3dnow");
numCpus = BSDStatsHelpers::getCpuInfo ("processor").getIntValue() + 1;
}
//==============================================================================
uint32 beast_millisecondsSinceStartup() noexcept
{
timespec t;
clock_gettime (CLOCK_MONOTONIC, &t);
return t.tv_sec * 1000 + t.tv_nsec / 1000000;
}
int64 Time::getHighResolutionTicks() noexcept
{
timespec t;
clock_gettime (CLOCK_MONOTONIC, &t);
return (t.tv_sec * (int64) 1000000) + (t.tv_nsec / 1000);
}
int64 Time::getHighResolutionTicksPerSecond() noexcept
{
return 1000000; // (microseconds)
}
double Time::getMillisecondCounterHiRes() noexcept
{
return getHighResolutionTicks() * 0.001;
}
bool Time::setSystemTimeToThisTime() const
{
timeval t;
t.tv_sec = millisSinceEpoch / 1000;
t.tv_usec = (millisSinceEpoch - t.tv_sec * 1000) * 1000;
return settimeofday (&t, 0) == 0;
}

View File

@@ -0,0 +1,85 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
Portions of this file are from JUCE.
Copyright (c) 2013 - Raw Material Software Ltd.
Please visit http://www.juce.com
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
/*
Note that a lot of methods that you'd expect to find in this file actually
live in beast_posix_SharedCode.h!
*/
//==============================================================================
void Process::setPriority (const ProcessPriority prior)
{
const int policy = (prior <= NormalPriority) ? SCHED_OTHER : SCHED_RR;
const int minp = sched_get_priority_min (policy);
const int maxp = sched_get_priority_max (policy);
struct sched_param param;
switch (prior)
{
case LowPriority:
case NormalPriority: param.sched_priority = 0; break;
case HighPriority: param.sched_priority = minp + (maxp - minp) / 4; break;
case RealtimePriority: param.sched_priority = minp + (3 * (maxp - minp) / 4); break;
default: bassertfalse; break;
}
pthread_setschedparam (pthread_self(), policy, &param);
}
void Process::terminate()
{
exit (0);
}
BEAST_API bool BEAST_CALLTYPE beast_isRunningUnderDebugger()
{
static char testResult = 0;
if (testResult == 0)
{
testResult = (char) ptrace (PT_TRACE_ME, 0, 0, 0);
if (testResult >= 0)
{
ptrace (PT_DETACH, 0, (caddr_t) 1, 0);
testResult = 1;
}
}
return testResult < 0;
}
BEAST_API bool BEAST_CALLTYPE Process::isRunningUnderDebugger()
{
return beast_isRunningUnderDebugger();
}
static void swapUserAndEffectiveUser()
{
(void) setreuid (geteuid(), getuid());
(void) setregid (getegid(), getgid());
}
void Process::raisePrivilege() { if (geteuid() != 0 && getuid() == 0) swapUserAndEffectiveUser(); }
void Process::lowerPrivilege() { if (geteuid() == 0 && getuid() != 0) swapUserAndEffectiveUser(); }

View File

@@ -27,7 +27,7 @@
//==============================================================================
/** Current BEAST version number.
See also SystemStats::getBEASTVersion() for a string version.
See also SystemStats::getBeastVersion() for a string version.
*/
#define BEAST_MAJOR_VERSION 0
#define BEAST_MINOR_VERSION 0
@@ -39,7 +39,7 @@
Bits 8 to 16 = minor version.
Bits 0 to 8 = point release.
See also SystemStats::getBEASTVersion() for a string version.
See also SystemStats::getBeastVersion() for a string version.
*/
#define BEAST_VERSION ((BEAST_MAJOR_VERSION << 16) + (BEAST_MINOR_VERSION << 8) + BEAST_BUILDNUMBER)

View File

@@ -27,7 +27,7 @@ const SystemStats::CPUFlags& SystemStats::getCPUFlags()
return cpuFlags;
}
String SystemStats::getBEASTVersion()
String SystemStats::getBeastVersion()
{
// Some basic tests, to keep an eye on things and make sure these types work ok
// on all platforms. Let me know if any of these assertions fail on your system!
@@ -41,7 +41,7 @@ String SystemStats::getBEASTVersion()
static_bassert (sizeof (int64) == 8);
static_bassert (sizeof (uint64) == 8);
return "BEAST v" BEAST_STRINGIFY(BEAST_MAJOR_VERSION)
return "Beast v" BEAST_STRINGIFY(BEAST_MAJOR_VERSION)
"." BEAST_STRINGIFY(BEAST_MINOR_VERSION)
"." BEAST_STRINGIFY(BEAST_BUILDNUMBER);
}
@@ -55,7 +55,7 @@ String SystemStats::getBEASTVersion()
{
BeastVersionPrinter()
{
DBG (SystemStats::getBEASTVersion());
DBG (SystemStats::getBeastVersion());
}
};

View File

@@ -26,7 +26,6 @@
#include "../text/beast_StringArray.h"
//==============================================================================
/**
Contains methods for finding out about the current hardware and OS configuration.
@@ -38,7 +37,7 @@ public:
/** Returns the current version of BEAST,
See also the BEAST_VERSION, BEAST_MAJOR_VERSION and BEAST_MINOR_VERSION macros.
*/
static String getBEASTVersion();
static String getBeastVersion();
//==============================================================================
/** The set of possible results of the getOperatingSystemType() method. */
@@ -46,16 +45,16 @@ public:
{
UnknownOS = 0,
Linux = 0x2000,
Android = 0x3000,
iOS = 0x8000,
MacOSX_10_4 = 0x1004,
MacOSX_10_5 = 0x1005,
MacOSX_10_6 = 0x1006,
MacOSX_10_7 = 0x1007,
MacOSX_10_8 = 0x1008,
Linux = 0x2000,
FreeBSD = 0x2001,
Android = 0x3000,
Win2000 = 0x4105,
WinXP = 0x4106,
WinVista = 0x4107,
@@ -64,6 +63,8 @@ public:
Windows = 0x4000, /**< To test whether any version of Windows is running,
you can use the expression ((getOperatingSystemType() & Windows) != 0). */
iOS = 0x8000
};
/** Returns the type of operating system we're running on.