And of course i forgot to add some files

This commit is contained in:
Siana Gearz
2012-03-06 09:11:36 +01:00
parent 83a3bbb48e
commit 1db7221508
15 changed files with 3337 additions and 0 deletions

View File

@@ -0,0 +1,97 @@
/**
* @file llareslistener.cpp
* @author Nat Goodspeed
* @date 2009-03-18
* @brief Implementation for llareslistener.
*
* $LicenseInfo:firstyear=2009&license=viewerlgpl$
* Second Life Viewer Source Code
* Copyright (C) 2010, Linden Research, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation;
* version 2.1 of the License only.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
* $/LicenseInfo$
*/
// Precompiled header
#include "linden_common.h"
// associated header
#include "llareslistener.h"
// STL headers
// std headers
// external library headers
// other Linden headers
#include "llares.h"
#include "llerror.h"
#include "llevents.h"
#include "llsdutil.h"
LLAresListener::LLAresListener(LLAres* llares):
LLEventAPI("LLAres",
"LLAres listener to request DNS operations"),
mAres(llares)
{
// add() every method we want to be able to invoke via this event API.
// Optional last parameter validates expected LLSD request structure.
add("rewriteURI",
"Given [\"uri\"], return on [\"reply\"] an array of alternative URIs.\n"
"On failure, returns an array containing only the original URI, so\n"
"failure case can be processed like success case.",
&LLAresListener::rewriteURI,
LLSD().with("uri", LLSD()).with("reply", LLSD()));
}
/// This UriRewriteResponder subclass packages returned URIs as an LLSD
/// array to send back to the requester.
class UriRewriteResponder: public LLAres::UriRewriteResponder
{
public:
/**
* Specify the request, containing the event pump name on which to send
* the reply.
*/
UriRewriteResponder(const LLSD& request):
mReqID(request),
mPumpName(request["reply"])
{}
/// Called by base class with results. This is called in both the
/// success and error cases. On error, the calling logic passes the
/// original URI.
virtual void rewriteResult(const std::vector<std::string>& uris)
{
LLSD result;
for (std::vector<std::string>::const_iterator ui(uris.begin()), uend(uris.end());
ui != uend; ++ui)
{
result.append(*ui);
}
// This call knows enough to avoid trying to insert a map key into an
// LLSD array. It's there so that if, for any reason, we ever decide
// to change the response from array to map, it will Just Start Working.
mReqID.stamp(result);
LLEventPumps::instance().obtain(mPumpName).post(result);
}
private:
LLReqID mReqID;
const std::string mPumpName;
};
void LLAresListener::rewriteURI(const LLSD& data)
{
mAres->rewriteURI(data["uri"], new UriRewriteResponder(data));
}

View File

@@ -0,0 +1,53 @@
/**
* @file llareslistener.h
* @author Nat Goodspeed
* @date 2009-03-18
* @brief LLEventPump API for LLAres. This header doesn't actually define the
* API; the API is defined by the pump name on which this class
* listens, and by the expected content of LLSD it receives.
*
* $LicenseInfo:firstyear=2009&license=viewerlgpl$
* Second Life Viewer Source Code
* Copyright (C) 2010, Linden Research, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation;
* version 2.1 of the License only.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
* $/LicenseInfo$
*/
#if ! defined(LL_LLARESLISTENER_H)
#define LL_LLARESLISTENER_H
#include "lleventapi.h"
class LLAres;
class LLSD;
/// Listen on an LLEventPump with specified name for LLAres request events.
class LLAresListener: public LLEventAPI
{
public:
/// Bind the LLAres instance to use (e.g. gAres)
LLAresListener(LLAres* llares);
private:
/// command["op"] == "rewriteURI"
void rewriteURI(const LLSD& data);
LLAres* mAres;
};
#endif /* ! defined(LL_LLARESLISTENER_H) */

546
indra/llmessage/llproxy.cpp Normal file
View File

@@ -0,0 +1,546 @@
/**
* @file llproxy.cpp
* @brief UDP and HTTP proxy communications
*
* $LicenseInfo:firstyear=2011&license=viewerlgpl$
* Second Life Viewer Source Code
* Copyright (C) 2011, Linden Research, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation;
* version 2.1 of the License only.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
* $/LicenseInfo$
*/
#include "linden_common.h"
#include "llproxy.h"
#include <string>
#include <curl/curl.h>
#include "llapr.h"
#include "llcurl.h"
#include "llhost.h"
// Static class variable instances
// We want this to be static to avoid excessive indirection on every
// incoming packet just to do a simple bool test. The getter for this
// member is also static
bool LLProxy::sUDPProxyEnabled = false;
// Some helpful TCP static functions.
static apr_status_t tcp_blocking_handshake(LLSocket::ptr_t handle, char * dataout, apr_size_t outlen, char * datain, apr_size_t maxinlen); // Do a TCP data handshake
static LLSocket::ptr_t tcp_open_channel(LLHost host); // Open a TCP channel to a given host
static void tcp_close_channel(LLSocket::ptr_t* handle_ptr); // Close an open TCP channel
LLProxy::LLProxy():
mHTTPProxyEnabled(false),
mProxyMutex(),
mUDPProxy(),
mTCPProxy(),
mHTTPProxy(),
mProxyType(LLPROXY_SOCKS),
mAuthMethodSelected(METHOD_NOAUTH),
mSocksUsername(),
mSocksPassword()
{
}
LLProxy::~LLProxy()
{
stopSOCKSProxy();
disableHTTPProxy();
}
/**
* @brief Open the SOCKS 5 TCP control channel.
*
* Perform a SOCKS 5 authentication and UDP association with the proxy server.
*
* @param proxy The SOCKS 5 server to connect to.
* @return SOCKS_OK if successful, otherwise a socks error code from llproxy.h.
*/
S32 LLProxy::proxyHandshake(LLHost proxy)
{
S32 result;
/* SOCKS 5 Auth request */
socks_auth_request_t socks_auth_request;
socks_auth_response_t socks_auth_response;
socks_auth_request.version = SOCKS_VERSION; // SOCKS version 5
socks_auth_request.num_methods = 1; // Sending 1 method.
socks_auth_request.methods = getSelectedAuthMethod(); // Send only the selected method.
result = tcp_blocking_handshake(mProxyControlChannel,
static_cast<char*>(static_cast<void*>(&socks_auth_request)),
sizeof(socks_auth_request),
static_cast<char*>(static_cast<void*>(&socks_auth_response)),
sizeof(socks_auth_response));
if (result != APR_SUCCESS)
{
LL_WARNS("Proxy") << "SOCKS authentication request failed, error on TCP control channel : " << result << LL_ENDL;
stopSOCKSProxy();
return SOCKS_CONNECT_ERROR;
}
if (socks_auth_response.method == AUTH_NOT_ACCEPTABLE)
{
LL_WARNS("Proxy") << "SOCKS 5 server refused all our authentication methods." << LL_ENDL;
stopSOCKSProxy();
return SOCKS_NOT_ACCEPTABLE;
}
/* SOCKS 5 USERNAME/PASSWORD authentication */
if (socks_auth_response.method == METHOD_PASSWORD)
{
// The server has requested a username/password combination
std::string socks_username(getSocksUser());
std::string socks_password(getSocksPwd());
U32 request_size = socks_username.size() + socks_password.size() + 3;
char * password_auth = new char[request_size];
password_auth[0] = 0x01;
password_auth[1] = socks_username.size();
memcpy(&password_auth[2], socks_username.c_str(), socks_username.size());
password_auth[socks_username.size() + 2] = socks_password.size();
memcpy(&password_auth[socks_username.size() + 3], socks_password.c_str(), socks_password.size());
authmethod_password_reply_t password_reply;
result = tcp_blocking_handshake(mProxyControlChannel,
password_auth,
request_size,
static_cast<char*>(static_cast<void*>(&password_reply)),
sizeof(password_reply));
delete[] password_auth;
if (result != APR_SUCCESS)
{
LL_WARNS("Proxy") << "SOCKS authentication failed, error on TCP control channel : " << result << LL_ENDL;
stopSOCKSProxy();
return SOCKS_CONNECT_ERROR;
}
if (password_reply.status != AUTH_SUCCESS)
{
LL_WARNS("Proxy") << "SOCKS authentication failed" << LL_ENDL;
stopSOCKSProxy();
return SOCKS_AUTH_FAIL;
}
}
/* SOCKS5 connect request */
socks_command_request_t connect_request;
socks_command_response_t connect_reply;
connect_request.version = SOCKS_VERSION; // SOCKS V5
connect_request.command = COMMAND_UDP_ASSOCIATE; // Associate UDP
connect_request.reserved = FIELD_RESERVED;
connect_request.atype = ADDRESS_IPV4;
connect_request.address = htonl(0); // 0.0.0.0
connect_request.port = htons(0); // 0
// "If the client is not in possession of the information at the time of the UDP ASSOCIATE,
// the client MUST use a port number and address of all zeros. RFC 1928"
result = tcp_blocking_handshake(mProxyControlChannel,
static_cast<char*>(static_cast<void*>(&connect_request)),
sizeof(connect_request),
static_cast<char*>(static_cast<void*>(&connect_reply)),
sizeof(connect_reply));
if (result != APR_SUCCESS)
{
LL_WARNS("Proxy") << "SOCKS connect request failed, error on TCP control channel : " << result << LL_ENDL;
stopSOCKSProxy();
return SOCKS_CONNECT_ERROR;
}
if (connect_reply.reply != REPLY_REQUEST_GRANTED)
{
LL_WARNS("Proxy") << "Connection to SOCKS 5 server failed, UDP forward request not granted" << LL_ENDL;
stopSOCKSProxy();
return SOCKS_UDP_FWD_NOT_GRANTED;
}
mUDPProxy.setPort(ntohs(connect_reply.port)); // reply port is in network byte order
mUDPProxy.setAddress(proxy.getAddress());
// The connection was successful. We now have the UDP port to send requests that need forwarding to.
LL_INFOS("Proxy") << "SOCKS 5 UDP proxy connected on " << mUDPProxy << LL_ENDL;
return SOCKS_OK;
}
/**
* @brief Initiates a SOCKS 5 proxy session.
*
* Performs basic checks on host to verify that it is a valid address. Opens the control channel
* and then negotiates the proxy connection with the server. Closes any existing SOCKS
* connection before proceeding. Also disables an HTTP proxy if it is using SOCKS as the proxy.
*
*
* @param host Socks server to connect to.
* @return SOCKS_OK if successful, otherwise a SOCKS error code defined in llproxy.h.
*/
S32 LLProxy::startSOCKSProxy(LLHost host)
{
if (host.isOk())
{
mTCPProxy = host;
}
else
{
return SOCKS_INVALID_HOST;
}
// Close any running SOCKS connection.
stopSOCKSProxy();
mProxyControlChannel = tcp_open_channel(mTCPProxy);
if (!mProxyControlChannel)
{
return SOCKS_HOST_CONNECT_FAILED;
}
S32 status = proxyHandshake(mTCPProxy);
if (status != SOCKS_OK)
{
// Shut down the proxy if any of the above steps failed.
stopSOCKSProxy();
}
else
{
// Connection was successful.
sUDPProxyEnabled = true;
}
return status;
}
/**
* @brief Stop using the SOCKS 5 proxy.
*
* This will stop sending UDP packets through the SOCKS 5 proxy
* and will also stop the HTTP proxy if it is configured to use SOCKS.
* The proxy control channel will also be disconnected.
*/
void LLProxy::stopSOCKSProxy()
{
sUDPProxyEnabled = false;
// If the SOCKS proxy is requested to stop and we are using that for HTTP as well
// then we must shut down any HTTP proxy operations. But it is allowable if web
// proxy is being used to continue proxying HTTP.
if (LLPROXY_SOCKS == getHTTPProxyType())
{
disableHTTPProxy();
}
if (mProxyControlChannel)
{
tcp_close_channel(&mProxyControlChannel);
}
}
/**
* @brief Set the proxy's SOCKS authentication method to none.
*/
void LLProxy::setAuthNone()
{
LLMutexLock lock(&mProxyMutex);
mAuthMethodSelected = METHOD_NOAUTH;
}
/**
* @brief Set the proxy's SOCKS authentication method to password.
*
* Check whether the lengths of the supplied username
* and password conform to the lengths allowed by the
* SOCKS protocol.
*
* @param username The SOCKS username to send.
* @param password The SOCKS password to send.
* @return Return true if applying the settings was successful. No changes are made if false.
*
*/
bool LLProxy::setAuthPassword(const std::string &username, const std::string &password)
{
if (username.length() > SOCKSMAXUSERNAMELEN || password.length() > SOCKSMAXPASSWORDLEN ||
username.length() < SOCKSMINUSERNAMELEN || password.length() < SOCKSMINPASSWORDLEN)
{
LL_WARNS("Proxy") << "Invalid SOCKS 5 password or username length." << LL_ENDL;
return false;
}
LLMutexLock lock(&mProxyMutex);
mAuthMethodSelected = METHOD_PASSWORD;
mSocksUsername = username;
mSocksPassword = password;
return true;
}
/**
* @brief Enable the HTTP proxy for either SOCKS or HTTP.
*
* Check the supplied host to see if it is a valid IP and port.
*
* @param httpHost Proxy server to connect to.
* @param type Is the host a SOCKS or HTTP proxy.
* @return Return true if applying the setting was successful. No changes are made if false.
*/
bool LLProxy::enableHTTPProxy(LLHost httpHost, LLHttpProxyType type)
{
if (!httpHost.isOk())
{
LL_WARNS("Proxy") << "Invalid SOCKS 5 Server" << LL_ENDL;
return false;
}
LLMutexLock lock(&mProxyMutex);
mHTTPProxy = httpHost;
mProxyType = type;
mHTTPProxyEnabled = true;
return true;
}
/**
* @brief Enable the HTTP proxy without changing the proxy settings.
*
* This should not be called unless the proxy has already been set up.
*
* @return Return true only if the current settings are valid and the proxy was enabled.
*/
bool LLProxy::enableHTTPProxy()
{
bool ok;
LLMutexLock lock(&mProxyMutex);
ok = (mHTTPProxy.isOk());
if (ok)
{
mHTTPProxyEnabled = true;
}
return ok;
}
/**
* @brief Disable the HTTP proxy.
*/
void LLProxy::disableHTTPProxy()
{
LLMutexLock lock(&mProxyMutex);
mHTTPProxyEnabled = false;
}
/**
* @brief Get the currently selected HTTP proxy type
*/
LLHttpProxyType LLProxy::getHTTPProxyType() const
{
LLMutexLock lock(&mProxyMutex);
return mProxyType;
}
/**
* @brief Get the SOCKS 5 password.
*/
std::string LLProxy::getSocksPwd() const
{
LLMutexLock lock(&mProxyMutex);
return mSocksPassword;
}
/**
* @brief Get the SOCKS 5 username.
*/
std::string LLProxy::getSocksUser() const
{
LLMutexLock lock(&mProxyMutex);
return mSocksUsername;
}
/**
* @brief Get the currently selected SOCKS 5 authentication method.
*
* @return Returns either none or password.
*/
LLSocks5AuthType LLProxy::getSelectedAuthMethod() const
{
LLMutexLock lock(&mProxyMutex);
return mAuthMethodSelected;
}
/**
* @brief Stop the LLProxy and make certain that any APR pools and classes are deleted before terminating APR.
*
* Deletes the LLProxy singleton, destroying the APR pool used by the control channel as well as .
*/
//static
void LLProxy::cleanupClass()
{
getInstance()->stopSOCKSProxy();
deleteSingleton();
}
void LLProxy::applyProxySettings(LLCurlEasyRequest* handle)
{
applyProxySettings(handle->getEasy());
}
void LLProxy::applyProxySettings(LLCurl::Easy* handle)
{
applyProxySettings(handle->getCurlHandle());
}
/**
* @brief Apply proxy settings to a CuRL request if an HTTP proxy is enabled.
*
* This method has been designed to be safe to call from
* any thread in the viewer. This allows requests in the
* texture fetch thread to be aware of the proxy settings.
* When the HTTP proxy is enabled, the proxy mutex will
* be locked every time this method is called.
*
* @param handle A pointer to a valid CURL request, before it has been performed.
*/
void LLProxy::applyProxySettings(CURL* handle)
{
// Do a faster unlocked check to see if we are supposed to proxy.
if (mHTTPProxyEnabled)
{
// We think we should proxy, lock the proxy mutex.
LLMutexLock lock(&mProxyMutex);
// Now test again to verify that the proxy wasn't disabled between the first check and the lock.
if (mHTTPProxyEnabled)
{
LLCurlFF::check_easy_code(curl_easy_setopt(handle, CURLOPT_PROXY, mHTTPProxy.getIPString().c_str()));
LLCurlFF::check_easy_code(curl_easy_setopt(handle, CURLOPT_PROXYPORT, mHTTPProxy.getPort()));
if (mProxyType == LLPROXY_SOCKS)
{
LLCurlFF::check_easy_code(curl_easy_setopt(handle, CURLOPT_PROXYTYPE, CURLPROXY_SOCKS5));
if (mAuthMethodSelected == METHOD_PASSWORD)
{
std::string auth_string = mSocksUsername + ":" + mSocksPassword;
LLCurlFF::check_easy_code(curl_easy_setopt(handle, CURLOPT_PROXYUSERPWD, auth_string.c_str()));
}
}
else
{
LLCurlFF::check_easy_code(curl_easy_setopt(handle, CURLOPT_PROXYTYPE, CURLPROXY_HTTP));
}
}
}
}
/**
* @brief Send one TCP packet and receive one in return.
*
* This operation is done synchronously with a 1000ms timeout. Therefore, it should not be used when a blocking
* operation would impact the operation of the viewer.
*
* @param handle_ptr Pointer to a connected LLSocket of type STREAM_TCP.
* @param dataout Data to send.
* @param outlen Length of dataout.
* @param datain Buffer for received data. Undefined if return value is not APR_SUCCESS.
* @param maxinlen Maximum possible length of received data. Short reads are allowed.
* @return Indicates APR status code of exchange. APR_SUCCESS if exchange was successful, -1 if invalid data length was received.
*/
static apr_status_t tcp_blocking_handshake(LLSocket::ptr_t handle, char * dataout, apr_size_t outlen, char * datain, apr_size_t maxinlen)
{
apr_socket_t* apr_socket = handle->getSocket();
apr_status_t rv = APR_SUCCESS;
apr_size_t expected_len = outlen;
handle->setBlocking(1000);
rv = apr_socket_send(apr_socket, dataout, &outlen);
if (APR_SUCCESS != rv)
{
LL_WARNS("Proxy") << "Error sending data to proxy control channel, status: " << rv << LL_ENDL;
ll_apr_warn_status(rv);
}
else if (expected_len != outlen)
{
LL_WARNS("Proxy") << "Incorrect data length sent. Expected: " << expected_len <<
" Sent: " << outlen << LL_ENDL;
rv = -1;
}
if (APR_SUCCESS == rv)
{
expected_len = maxinlen;
rv = apr_socket_recv(apr_socket, datain, &maxinlen);
if (rv != APR_SUCCESS)
{
LL_WARNS("Proxy") << "Error receiving data from proxy control channel, status: " << rv << LL_ENDL;
ll_apr_warn_status(rv);
}
else if (expected_len < maxinlen)
{
LL_WARNS("Proxy") << "Incorrect data length received. Expected: " << expected_len <<
" Received: " << maxinlen << LL_ENDL;
rv = -1;
}
}
handle->setNonBlocking();
return rv;
}
/**
* @brief Open a LLSocket and do a blocking connect to the chosen host.
*
* Checks for a successful connection, and makes sure the connection is closed if it fails.
*
* @param host The host to open the connection to.
* @return The created socket. Will evaluate as NULL if the connection is unsuccessful.
*/
static LLSocket::ptr_t tcp_open_channel(LLHost host)
{
LLSocket::ptr_t socket = LLSocket::create(LLSocket::STREAM_TCP);
bool connected = socket->blockingConnect(host);
if (!connected)
{
tcp_close_channel(&socket);
}
return socket;
}
/**
* @brief Close the socket.
*
* @param handle_ptr The handle of the socket being closed. A pointer-to-pointer to avoid increasing the use count.
*/
static void tcp_close_channel(LLSocket::ptr_t* handle_ptr)
{
LL_DEBUGS("Proxy") << "Resetting proxy LLSocket handle, use_count == " << handle_ptr->use_count() << LL_ENDL;
handle_ptr->reset();
}

352
indra/llmessage/llproxy.h Normal file
View File

@@ -0,0 +1,352 @@
/**
* @file llproxy.h
* @brief UDP and HTTP proxy communications
*
* $LicenseInfo:firstyear=2011&license=viewerlgpl$
* Second Life Viewer Source Code
* Copyright (C) 2011, Linden Research, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation;
* version 2.1 of the License only.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
* $/LicenseInfo$
*/
#ifndef LL_PROXY_H
#define LL_PROXY_H
#include "llcurl.h"
#include "llhost.h"
#include "lliosocket.h"
#include "llmemory.h"
#include "llsingleton.h"
#include "llthread.h"
#include <string>
// SOCKS error codes returned from the StartProxy method
#define SOCKS_OK 0
#define SOCKS_CONNECT_ERROR (-1)
#define SOCKS_NOT_PERMITTED (-2)
#define SOCKS_NOT_ACCEPTABLE (-3)
#define SOCKS_AUTH_FAIL (-4)
#define SOCKS_UDP_FWD_NOT_GRANTED (-5)
#define SOCKS_HOST_CONNECT_FAILED (-6)
#define SOCKS_INVALID_HOST (-7)
#ifndef MAXHOSTNAMELEN
#define MAXHOSTNAMELEN (255 + 1) /* socks5: 255, +1 for len. */
#endif
#define SOCKSMAXUSERNAMELEN 255
#define SOCKSMAXPASSWORDLEN 255
#define SOCKSMINUSERNAMELEN 1
#define SOCKSMINPASSWORDLEN 1
#define SOCKS_VERSION 0x05 // we are using SOCKS 5
#define SOCKS_HEADER_SIZE 10
// SOCKS 5 address/hostname types
#define ADDRESS_IPV4 0x01
#define ADDRESS_HOSTNAME 0x03
#define ADDRESS_IPV6 0x04
// Lets just use our own ipv4 struct rather than dragging in system
// specific headers
union ipv4_address_t {
U8 octets[4];
U32 addr32;
};
// SOCKS 5 control channel commands
#define COMMAND_TCP_STREAM 0x01
#define COMMAND_TCP_BIND 0x02
#define COMMAND_UDP_ASSOCIATE 0x03
// SOCKS 5 command replies
#define REPLY_REQUEST_GRANTED 0x00
#define REPLY_GENERAL_FAIL 0x01
#define REPLY_RULESET_FAIL 0x02
#define REPLY_NETWORK_UNREACHABLE 0x03
#define REPLY_HOST_UNREACHABLE 0x04
#define REPLY_CONNECTION_REFUSED 0x05
#define REPLY_TTL_EXPIRED 0x06
#define REPLY_PROTOCOL_ERROR 0x07
#define REPLY_TYPE_NOT_SUPPORTED 0x08
#define FIELD_RESERVED 0x00
// The standard SOCKS 5 request packet
// Push current alignment to stack and set alignment to 1 byte boundary
// This enabled us to use structs directly to set up and receive network packets
// into the correct fields, without fear of boundary alignment causing issues
#pragma pack(push,1)
// SOCKS 5 command packet
struct socks_command_request_t {
U8 version;
U8 command;
U8 reserved;
U8 atype;
U32 address;
U16 port;
};
// Standard SOCKS 5 reply packet
struct socks_command_response_t {
U8 version;
U8 reply;
U8 reserved;
U8 atype;
U8 add_bytes[4];
U16 port;
};
#define AUTH_NOT_ACCEPTABLE 0xFF // reply if preferred methods are not available
#define AUTH_SUCCESS 0x00 // reply if authentication successful
// SOCKS 5 authentication request, stating which methods the client supports
struct socks_auth_request_t {
U8 version;
U8 num_methods;
U8 methods; // We are only using a single method currently
};
// SOCKS 5 authentication response packet, stating server preferred method
struct socks_auth_response_t {
U8 version;
U8 method;
};
// SOCKS 5 password reply packet
struct authmethod_password_reply_t {
U8 version;
U8 status;
};
// SOCKS 5 UDP packet header
struct proxywrap_t {
U16 rsv;
U8 frag;
U8 atype;
U32 addr;
U16 port;
};
#pragma pack(pop) /* restore original alignment from stack */
// Currently selected HTTP proxy type
enum LLHttpProxyType
{
LLPROXY_SOCKS = 0,
LLPROXY_HTTP = 1
};
// Auth types
enum LLSocks5AuthType
{
METHOD_NOAUTH = 0x00, // Client supports no auth
METHOD_GSSAPI = 0x01, // Client supports GSSAPI (Not currently supported)
METHOD_PASSWORD = 0x02 // Client supports username/password
};
/**
* @brief Manage SOCKS 5 UDP proxy and HTTP proxy.
*
* This class is responsible for managing two interconnected tasks,
* connecting to a SOCKS 5 proxy for use by LLPacketRing to send UDP
* packets and managing proxy settings for HTTP requests.
*
* <h1>Threading:</h1>
* Because HTTP requests can be generated in threads outside the
* main thread, it is necessary for some of the information stored
* by this class to be available to other threads. The members that
* need to be read across threads are in a labeled section below.
* To protect those members, a mutex, mProxyMutex should be locked
* before reading or writing those members. Methods that can lock
* mProxyMutex are in a labeled section below. Those methods should
* not be called while the mutex is already locked.
*
* There is also a LLAtomic type flag (mHTTPProxyEnabled) that is used
* to track whether the HTTP proxy is currently enabled. This allows
* for faster unlocked checks to see if the proxy is enabled. This
* allows us to cut down on the performance hit when the proxy is
* disabled compared to before this class was introduced.
*
* <h1>UDP Proxying:</h1>
* UDP datagrams are proxied via a SOCKS 5 proxy with the UDP associate
* command. To initiate the proxy, a TCP socket connection is opened
* to the SOCKS 5 host, and after a handshake exchange, the server
* returns a port and address to send the UDP traffic that is to be
* proxied to. The LLProxy class tracks this address and port after the
* exchange and provides it to LLPacketRing when required to. All UDP
* proxy management occurs in the main thread.
*
* <h1>HTTP Proxying:</h1>
* This class allows all viewer HTTP packets to be sent through a proxy.
* The user can select whether to send HTTP packets through a standard
* "web" HTTP proxy, through a SOCKS 5 proxy, or to not proxy HTTP
* communication. This class does not manage the integrated web browser
* proxy, which is handled in llviewermedia.cpp.
*
* The implementation of HTTP proxying is handled by libcurl. LLProxy
* is responsible for managing the HTTP proxy options and provides a
* thread-safe method to apply those options to a curl request
* (LLProxy::applyProxySettings()). This method is overloaded
* to accommodate the various abstraction libcurl layers that exist
* throughout the viewer (LLCurlEasyRequest, LLCurl::Easy, and CURL).
*
* If you are working with LLCurl or LLCurlEasyRequest objects,
* the configured proxy settings will be applied in the constructors
* of those request handles. If you are working with CURL objects
* directly, you will need to pass the handle of the request to
* applyProxySettings() before issuing the request.
*
* To ensure thread safety, all LLProxy members that relate to the HTTP
* proxy require the LLProxyMutex to be locked before accessing.
*/
class LLProxy: public LLSingleton<LLProxy>
{
LOG_CLASS(LLProxy);
public:
/*###########################################################################################
METHODS THAT DO NOT LOCK mProxyMutex!
###########################################################################################*/
// Constructor, cannot have parameters due to LLSingleton parent class. Call from main thread only.
LLProxy();
// Static check for enabled status for UDP packets. Call from main thread only.
static bool isSOCKSProxyEnabled() { return sUDPProxyEnabled; }
// Get the UDP proxy address and port. Call from main thread only.
LLHost getUDPProxy() const { return mUDPProxy; }
/*###########################################################################################
END OF NON-LOCKING METHODS
###########################################################################################*/
/*###########################################################################################
METHODS THAT LOCK mProxyMutex! DO NOT CALL WHILE mProxyMutex IS LOCKED!
###########################################################################################*/
// Destructor, closes open connections. Do not call directly, use cleanupClass().
~LLProxy();
// Delete LLProxy singleton. Allows the apr_socket used in the SOCKS 5 control channel to be
// destroyed before the call to apr_terminate. Call from main thread only.
static void cleanupClass();
// Apply the current proxy settings to a curl request. Doesn't do anything if mHTTPProxyEnabled is false.
// Safe to call from any thread.
void applyProxySettings(CURL* handle);
void applyProxySettings(LLCurl::Easy* handle);
void applyProxySettings(LLCurlEasyRequest* handle);
// Start a connection to the SOCKS 5 proxy. Call from main thread only.
S32 startSOCKSProxy(LLHost host);
// Disconnect and clean up any connection to the SOCKS 5 proxy. Call from main thread only.
void stopSOCKSProxy();
// Use Password auth when connecting to the SOCKS proxy. Call from main thread only.
bool setAuthPassword(const std::string &username, const std::string &password);
// Disable authentication when connecting to the SOCKS proxy. Call from main thread only.
void setAuthNone();
// Proxy HTTP packets via httpHost, which can be a SOCKS 5 or a HTTP proxy.
// as specified in type. Call from main thread only.
bool enableHTTPProxy(LLHost httpHost, LLHttpProxyType type);
bool enableHTTPProxy();
// Stop proxying HTTP packets. Call from main thread only.
void disableHTTPProxy();
/*###########################################################################################
END OF LOCKING METHODS
###########################################################################################*/
private:
/*###########################################################################################
METHODS THAT LOCK mProxyMutex! DO NOT CALL WHILE mProxyMutex IS LOCKED!
###########################################################################################*/
// Perform a SOCKS 5 authentication and UDP association with the proxy server.
S32 proxyHandshake(LLHost proxy);
// Get the currently selected auth method.
LLSocks5AuthType getSelectedAuthMethod() const;
// Get the currently selected HTTP proxy type
LLHttpProxyType getHTTPProxyType() const;
std::string getSocksPwd() const;
std::string getSocksUser() const;
/*###########################################################################################
END OF LOCKING METHODS
###########################################################################################*/
private:
// Is the HTTP proxy enabled? Safe to read in any thread, but do not write directly.
// Instead use enableHTTPProxy() and disableHTTPProxy() instead.
mutable LLAtomic32<bool> mHTTPProxyEnabled;
// Mutex to protect shared members in non-main thread calls to applyProxySettings().
mutable LLMutex mProxyMutex;
/*###########################################################################################
MEMBERS READ AND WRITTEN ONLY IN THE MAIN THREAD. DO NOT SHARE!
###########################################################################################*/
// Is the UDP proxy enabled?
static bool sUDPProxyEnabled;
// UDP proxy address and port
LLHost mUDPProxy;
// TCP proxy control channel address and port
LLHost mTCPProxy;
// socket handle to proxy TCP control channel
LLSocket::ptr_t mProxyControlChannel;
/*###########################################################################################
END OF UNSHARED MEMBERS
###########################################################################################*/
/*###########################################################################################
MEMBERS WRITTEN IN MAIN THREAD AND READ IN ANY THREAD. ONLY READ OR WRITE AFTER LOCKING mProxyMutex!
###########################################################################################*/
// HTTP proxy address and port
LLHost mHTTPProxy;
// Currently selected HTTP proxy type. Can be web or socks.
LLHttpProxyType mProxyType;
// SOCKS 5 selected authentication method.
LLSocks5AuthType mAuthMethodSelected;
// SOCKS 5 username
std::string mSocksUsername;
// SOCKS 5 password
std::string mSocksPassword;
/*###########################################################################################
END OF SHARED MEMBERS
###########################################################################################*/
};
#endif

View File

@@ -0,0 +1,217 @@
/**
* @file llareslistener_test.cpp
* @author Mark Palange
* @date 2009-02-26
* @brief Tests of llareslistener.h.
*
* $LicenseInfo:firstyear=2009&license=viewerlgpl$
* Second Life Viewer Source Code
* Copyright (C) 2010, Linden Research, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation;
* version 2.1 of the License only.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
* $/LicenseInfo$
*/
#if LL_WINDOWS
#pragma warning (disable : 4355) // 'this' used in initializer list: yes, intentionally
#endif
// Precompiled header
#include "linden_common.h"
// associated header
#include "../llareslistener.h"
// STL headers
#include <iostream>
// std headers
// external library headers
#include <boost/bind.hpp>
// other Linden headers
#include "llsd.h"
#include "llares.h"
#include "../test/lltut.h"
#include "llevents.h"
#include "tests/wrapllerrs.h"
/*****************************************************************************
* Dummy stuff
*****************************************************************************/
LLAres::LLAres():
// Simulate this much of the real LLAres constructor: we need an
// LLAresListener instance.
mListener(new LLAresListener("LLAres", this))
{}
LLAres::~LLAres() {}
void LLAres::rewriteURI(const std::string &uri,
LLAres::UriRewriteResponder *resp)
{
// This is the only LLAres method I chose to implement.
// The effect is that LLAres returns immediately with
// a result that is equal to the input uri.
std::vector<std::string> result;
result.push_back(uri);
resp->rewriteResult(result);
}
LLAres::QueryResponder::~QueryResponder() {}
void LLAres::QueryResponder::queryError(int) {}
void LLAres::QueryResponder::queryResult(char const*, size_t) {}
LLQueryResponder::LLQueryResponder() {}
void LLQueryResponder::queryResult(char const*, size_t) {}
void LLQueryResponder::querySuccess() {}
void LLAres::UriRewriteResponder::queryError(int) {}
void LLAres::UriRewriteResponder::querySuccess() {}
void LLAres::UriRewriteResponder::rewriteResult(const std::vector<std::string>& uris) {}
/*****************************************************************************
* TUT
*****************************************************************************/
namespace tut
{
struct data
{
LLAres dummyAres;
};
typedef test_group<data> llareslistener_group;
typedef llareslistener_group::object object;
llareslistener_group llareslistenergrp("llareslistener");
struct ResponseCallback
{
std::vector<std::string> mURIs;
bool operator()(const LLSD& response)
{
mURIs.clear();
for (LLSD::array_const_iterator ri(response.beginArray()), rend(response.endArray());
ri != rend; ++ri)
{
mURIs.push_back(*ri);
}
return false;
}
};
template<> template<>
void object::test<1>()
{
set_test_name("test event");
// Tests the success and failure cases, since they both use
// the same code paths in the LLAres responder.
ResponseCallback response;
std::string pumpname("trigger");
// Since we're asking LLEventPumps to obtain() the pump by the desired
// name, it will persist beyond the current scope, so ensure we
// disconnect from it when 'response' goes away.
LLTempBoundListener temp(
LLEventPumps::instance().obtain(pumpname).listen("rewriteURIresponse",
boost::bind(&ResponseCallback::operator(), &response, _1)));
// Now build an LLSD request that will direct its response events to
// that pump.
const std::string testURI("login.bar.com");
LLSD request;
request["op"] = "rewriteURI";
request["uri"] = testURI;
request["reply"] = pumpname;
LLEventPumps::instance().obtain("LLAres").post(request);
ensure_equals(response.mURIs.size(), 1);
ensure_equals(response.mURIs.front(), testURI);
}
template<> template<>
void object::test<2>()
{
set_test_name("bad op");
WrapLL_ERRS capture;
LLSD request;
request["op"] = "foo";
std::string threw;
try
{
LLEventPumps::instance().obtain("LLAres").post(request);
}
catch (const WrapLL_ERRS::FatalException& e)
{
threw = e.what();
}
ensure_contains("LLAresListener bad op", threw, "bad");
}
template<> template<>
void object::test<3>()
{
set_test_name("bad rewriteURI request");
WrapLL_ERRS capture;
LLSD request;
request["op"] = "rewriteURI";
std::string threw;
try
{
LLEventPumps::instance().obtain("LLAres").post(request);
}
catch (const WrapLL_ERRS::FatalException& e)
{
threw = e.what();
}
ensure_contains("LLAresListener bad req", threw, "missing");
ensure_contains("LLAresListener bad req", threw, "reply");
ensure_contains("LLAresListener bad req", threw, "uri");
}
template<> template<>
void object::test<4>()
{
set_test_name("bad rewriteURI request");
WrapLL_ERRS capture;
LLSD request;
request["op"] = "rewriteURI";
request["reply"] = "nonexistent";
std::string threw;
try
{
LLEventPumps::instance().obtain("LLAres").post(request);
}
catch (const WrapLL_ERRS::FatalException& e)
{
threw = e.what();
}
ensure_contains("LLAresListener bad req", threw, "missing");
ensure_contains("LLAresListener bad req", threw, "uri");
ensure_does_not_contain("LLAresListener bad req", threw, "reply");
}
template<> template<>
void object::test<5>()
{
set_test_name("bad rewriteURI request");
WrapLL_ERRS capture;
LLSD request;
request["op"] = "rewriteURI";
request["uri"] = "foo.bar.com";
std::string threw;
try
{
LLEventPumps::instance().obtain("LLAres").post(request);
}
catch (const WrapLL_ERRS::FatalException& e)
{
threw = e.what();
}
ensure_contains("LLAresListener bad req", threw, "missing");
ensure_contains("LLAresListener bad req", threw, "reply");
ensure_does_not_contain("LLAresListener bad req", threw, "uri");
}
}

View File

@@ -0,0 +1,102 @@
/**
* @file llavatarnamecache_test.cpp
* @author James Cook
* @brief LLAvatarNameCache test cases.
*
* $LicenseInfo:firstyear=2010&license=viewerlgpl$
* Second Life Viewer Source Code
* Copyright (C) 2010, Linden Research, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation;
* version 2.1 of the License only.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
* $/LicenseInfo$
*/
#include "linden_common.h"
#include "../llavatarnamecache.h"
#include "../test/lltut.h"
namespace tut
{
struct avatarnamecache_data
{
};
typedef test_group<avatarnamecache_data> avatarnamecache_test;
typedef avatarnamecache_test::object avatarnamecache_object;
tut::avatarnamecache_test avatarnamecache_testcase("LLAvatarNameCache");
template<> template<>
void avatarnamecache_object::test<1>()
{
bool valid = false;
S32 max_age = 0;
valid = max_age_from_cache_control("max-age=3600", &max_age);
ensure("typical input valid", valid);
ensure_equals("typical input parsed", max_age, 3600);
valid = max_age_from_cache_control(
" max-age=600 , no-cache,private=\"stuff\" ", &max_age);
ensure("complex input valid", valid);
ensure_equals("complex input parsed", max_age, 600);
valid = max_age_from_cache_control(
"no-cache, max-age = 123 ", &max_age);
ensure("complex input 2 valid", valid);
ensure_equals("complex input 2 parsed", max_age, 123);
}
template<> template<>
void avatarnamecache_object::test<2>()
{
bool valid = false;
S32 max_age = -1;
valid = max_age_from_cache_control("", &max_age);
ensure("empty input returns invalid", !valid);
ensure_equals("empty input doesn't change val", max_age, -1);
valid = max_age_from_cache_control("no-cache", &max_age);
ensure("no max-age field returns invalid", !valid);
valid = max_age_from_cache_control("max", &max_age);
ensure("just 'max' returns invalid", !valid);
valid = max_age_from_cache_control("max-age", &max_age);
ensure("partial max-age is invalid", !valid);
valid = max_age_from_cache_control("max-age=", &max_age);
ensure("longer partial max-age is invalid", !valid);
valid = max_age_from_cache_control("max-age=FOO", &max_age);
ensure("invalid integer max-age is invalid", !valid);
valid = max_age_from_cache_control("max-age 234", &max_age);
ensure("space separated max-age is invalid", !valid);
valid = max_age_from_cache_control("max-age=0", &max_age);
ensure("zero max-age is valid", valid);
// *TODO: Handle "0000" as zero
//valid = max_age_from_cache_control("max-age=0000", &max_age);
//ensure("multi-zero max-age is valid", valid);
valid = max_age_from_cache_control("max-age=-123", &max_age);
ensure("less than zero max-age is invalid", !valid);
}
}

View File

@@ -0,0 +1,251 @@
/**
* @file llhost_test.cpp
* @author Adroit
* @date 2007-02
* @brief llhost test cases.
*
* $LicenseInfo:firstyear=2007&license=viewerlgpl$
* Second Life Viewer Source Code
* Copyright (C) 2010, Linden Research, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation;
* version 2.1 of the License only.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
* $/LicenseInfo$
*/
#include "linden_common.h"
#include "../llhost.h"
#include "../test/lltut.h"
namespace tut
{
struct host_data
{
};
typedef test_group<host_data> host_test;
typedef host_test::object host_object;
tut::host_test host_testcase("LLHost");
template<> template<>
void host_object::test<1>()
{
LLHost host;
ensure("IP address is not NULL", (0 == host.getAddress()) && (0 == host.getPort()) && !host.isOk());
}
template<> template<>
void host_object::test<2>()
{
U32 ip_addr = 0xc098017d;
U32 port = 8080;
LLHost host(ip_addr, port);
ensure("IP address is invalid", ip_addr == host.getAddress());
ensure("Port Number is invalid", port == host.getPort());
ensure("IP address and port number both should be ok", host.isOk());
}
template<> template<>
void host_object::test<3>()
{
const char* str = "192.168.1.1";
U32 port = 8080;
LLHost host(str, port);
ensure("IP address could not be processed", (host.getAddress() == ip_string_to_u32(str)));
ensure("Port Number is invalid", (port == host.getPort()));
}
template<> template<>
void host_object::test<4>()
{
U32 ip = ip_string_to_u32("192.168.1.1");
U32 port = 22;
U64 ip_port = (((U64) ip) << 32) | port;
LLHost host(ip_port);
ensure("IP address is invalid", ip == host.getAddress());
ensure("Port Number is invalid", port == host.getPort());
}
template<> template<>
void host_object::test<5>()
{
std::string ip_port_string = "192.168.1.1:8080";
U32 ip = ip_string_to_u32("192.168.1.1");
U32 port = 8080;
LLHost host(ip_port_string);
ensure("IP address from IP:port is invalid", ip == host.getAddress());
ensure("Port Number from from IP:port is invalid", port == host.getPort());
}
template<> template<>
void host_object::test<6>()
{
U32 ip = 0xc098017d, port = 8080;
LLHost host;
host.set(ip,port);
ensure("IP address is invalid", (ip == host.getAddress()));
ensure("Port Number is invalid", (port == host.getPort()));
}
template<> template<>
void host_object::test<7>()
{
const char* str = "192.168.1.1";
U32 port = 8080, ip;
LLHost host;
host.set(str,port);
ip = ip_string_to_u32(str);
ensure("IP address is invalid", (ip == host.getAddress()));
ensure("Port Number is invalid", (port == host.getPort()));
str = "64.233.187.99";
ip = ip_string_to_u32(str);
host.setAddress(str);
ensure("IP address is invalid", (ip == host.getAddress()));
ip = 0xc098017b;
host.setAddress(ip);
ensure("IP address is invalid", (ip == host.getAddress()));
// should still use the old port
ensure("Port Number is invalid", (port == host.getPort()));
port = 8084;
host.setPort(port);
ensure("Port Number is invalid", (port == host.getPort()));
// should still use the old address
ensure("IP address is invalid", (ip == host.getAddress()));
}
template<> template<>
void host_object::test<8>()
{
const std::string str("192.168.1.1");
U32 port = 8080;
LLHost host;
host.set(str,port);
std::string ip_string = host.getIPString();
ensure("Function Failed", (ip_string == str));
std::string ip_string_port = host.getIPandPort();
ensure("Function Failed", (ip_string_port == "192.168.1.1:8080"));
}
// getHostName() and setHostByName
template<> template<>
void host_object::test<9>()
{
skip("this test is flaky, but we should figure out why...");
// skip("setHostByName(\"google.com\"); getHostName() -> (e.g.) \"yx-in-f100.1e100.net\"");
std::string hostStr = "lindenlab.com";
LLHost host;
host.setHostByName(hostStr);
// reverse DNS will likely result in appending of some
// sub-domain to the main hostname. so look for
// the main domain name and not do the exact compare
std::string hostname = host.getHostName();
try
{
ensure("getHostName failed", hostname.find(hostStr) != std::string::npos);
}
catch (const std::exception&)
{
std::cerr << "set '" << hostStr << "'; reported '" << hostname << "'" << std::endl;
throw;
}
}
// setHostByName for dotted IP
template<> template<>
void host_object::test<10>()
{
std::string hostStr = "64.233.167.99";
LLHost host;
host.setHostByName(hostStr);
ensure("SetHostByName for dotted IP Address failed", host.getAddress() == ip_string_to_u32(hostStr.c_str()));
}
template<> template<>
void host_object::test<11>()
{
LLHost host1(0xc098017d, 8080);
LLHost host2 = host1;
ensure("Both IP addresses are not same", (host1.getAddress() == host2.getAddress()));
ensure("Both port numbers are not same", (host1.getPort() == host2.getPort()));
}
template<> template<>
void host_object::test<12>()
{
LLHost host1("192.168.1.1", 8080);
std::string str1 = "192.168.1.1:8080";
std::ostringstream stream;
stream << host1;
ensure("Operator << failed", ( stream.str()== str1));
// There is no istream >> llhost operator.
//std::istringstream is(stream.str());
//LLHost host2;
//is >> host2;
//ensure("Operator >> failed. Not compatible with <<", host1 == host2);
}
// operators ==, !=, <
template<> template<>
void host_object::test<13>()
{
U32 ip_addr = 0xc098017d;
U32 port = 8080;
LLHost host1(ip_addr, port);
LLHost host2(ip_addr, port);
ensure("operator== failed", host1 == host2);
// change port
host2.setPort(7070);
ensure("operator!= failed", host1 != host2);
// set port back to 8080 and change IP address now
host2.setPort(8080);
host2.setAddress(ip_addr+10);
ensure("operator!= failed", host1 != host2);
ensure("operator< failed", host1 < host2);
// set IP address back to same value and change port
host2.setAddress(ip_addr);
host2.setPort(host1.getPort() + 10);
ensure("operator< failed", host1 < host2);
}
// invalid ip address string
template<> template<>
void host_object::test<14>()
{
LLHost host1("10.0.1.2", 6143);
ensure("10.0.1.2 should be a valid address", host1.isOk());
LLHost host2("booger-brains", 6143);
ensure("booger-brains should be an invalid ip addess", !host2.isOk());
LLHost host3("255.255.255.255", 6143);
ensure("255.255.255.255 should be valid broadcast address", host3.isOk());
}
}

View File

@@ -0,0 +1,445 @@
/**
* @file llmime_test.cpp
* @author Phoenix
* @date 2006-12-24
* @brief BRIEF_DESC of llmime_test.cpp
*
* $LicenseInfo:firstyear=2006&license=viewerlgpl$
* Second Life Viewer Source Code
* Copyright (C) 2010, Linden Research, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation;
* version 2.1 of the License only.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
* $/LicenseInfo$
*/
#include "linden_common.h"
#include "llsdserialize.h"
#include "../llmime.h"
#include "../test/lltut.h"
namespace tut
{
struct mime_index
{
};
typedef test_group<mime_index> mime_index_t;
typedef mime_index_t::object mime_index_object_t;
tut::mime_index_t tut_mime_index("LLMime");
template<> template<>
void mime_index_object_t::test<1>()
{
LLMimeIndex mime;
ensure("no headers", mime.headers().isUndefined());
ensure_equals("invalid offset", mime.offset(), -1);
ensure_equals("invalid content length", mime.contentLength(), -1);
ensure("no content type", mime.contentType().empty());
ensure("not multipart", !mime.isMultipart());
ensure_equals("no attachments", mime.subPartCount(), 0);
}
template<> template<>
void mime_index_object_t::test<2>()
{
const S32 CONTENT_LENGTH = 6000;
const S32 CONTENT_OFFSET = 100;
const std::string CONTENT_TYPE = std::string("image/j2c");
LLSD headers;
headers["Content-Length"] = CONTENT_LENGTH;
headers["Content-Type"] = CONTENT_TYPE;
LLMimeIndex mime(headers, CONTENT_OFFSET);
ensure("headers are map", mime.headers().isMap());
ensure_equals("offset", mime.offset(), CONTENT_OFFSET);
ensure_equals("content length", mime.contentLength(), CONTENT_LENGTH);
ensure_equals("type is image/j2c", mime.contentType(), CONTENT_TYPE);
ensure("not multipart", !mime.isMultipart());
ensure_equals("no attachments", mime.subPartCount(), 0);
}
template<> template<>
void mime_index_object_t::test<3>()
{
const S32 MULTI_CONTENT_LENGTH = 8000;
const S32 MULTI_CONTENT_OFFSET = 100;
const std::string MULTI_CONTENT_TYPE = std::string("multipart/mixed");
LLSD headers;
headers["Content-Length"] = MULTI_CONTENT_LENGTH;
headers["Content-Type"] = MULTI_CONTENT_TYPE;
LLMimeIndex mime(headers, MULTI_CONTENT_OFFSET);
llinfos << "headers: " << LLSDOStreamer<LLSDNotationFormatter>(headers)
<< llendl;
const S32 META_CONTENT_LENGTH = 700;
const S32 META_CONTENT_OFFSET = 69;
const std::string META_CONTENT_TYPE = std::string(
"text/llsd+xml");
headers = LLSD::emptyMap();
headers["Content-Length"] = META_CONTENT_LENGTH;
headers["Content-Type"] = META_CONTENT_TYPE;
LLMimeIndex meta(headers, META_CONTENT_OFFSET);
mime.attachSubPart(meta);
const S32 IMAGE_CONTENT_LENGTH = 6000;
const S32 IMAGE_CONTENT_OFFSET = 200;
const std::string IMAGE_CONTENT_TYPE = std::string("image/j2c");
headers = LLSD::emptyMap();
headers["Content-Length"] = IMAGE_CONTENT_LENGTH;
headers["Content-Type"] = IMAGE_CONTENT_TYPE;
LLMimeIndex image(headers, IMAGE_CONTENT_OFFSET);
mime.attachSubPart(image);
// make sure we have a valid multi-part
ensure("is multipart", mime.isMultipart());
ensure_equals("multi offset", mime.offset(), MULTI_CONTENT_OFFSET);
ensure_equals(
"multi content length",
mime.contentLength(),
MULTI_CONTENT_LENGTH);
ensure_equals("two attachments", mime.subPartCount(), 2);
// make sure ranged gets do the right thing with out of bounds
// sub-parts.
LLMimeIndex invalid_child(mime.subPart(-1));
ensure("no headers", invalid_child.headers().isUndefined());
ensure_equals("invalid offset", invalid_child.offset(), -1);
ensure_equals(
"invalid content length", invalid_child.contentLength(), -1);
ensure("no content type", invalid_child.contentType().empty());
ensure("not multipart", !invalid_child.isMultipart());
ensure_equals("no attachments", invalid_child.subPartCount(), 0);
invalid_child = mime.subPart(2);
ensure("no headers", invalid_child.headers().isUndefined());
ensure_equals("invalid offset", invalid_child.offset(), -1);
ensure_equals(
"invalid content length", invalid_child.contentLength(), -1);
ensure("no content type", invalid_child.contentType().empty());
ensure("not multipart", !invalid_child.isMultipart());
ensure_equals("no attachments", invalid_child.subPartCount(), 0);
}
template<> template<>
void mime_index_object_t::test<4>()
{
const S32 MULTI_CONTENT_LENGTH = 8000;
const S32 MULTI_CONTENT_OFFSET = 100;
const std::string MULTI_CONTENT_TYPE = std::string("multipart/mixed");
LLSD headers;
headers["Content-Length"] = MULTI_CONTENT_LENGTH;
headers["Content-Type"] = MULTI_CONTENT_TYPE;
LLMimeIndex mime(headers, MULTI_CONTENT_OFFSET);
const S32 META_CONTENT_LENGTH = 700;
const S32 META_CONTENT_OFFSET = 69;
const std::string META_CONTENT_TYPE = std::string(
"application/llsd+xml");
headers = LLSD::emptyMap();
headers["Content-Length"] = META_CONTENT_LENGTH;
headers["Content-Type"] = META_CONTENT_TYPE;
LLMimeIndex meta(headers, META_CONTENT_OFFSET);
mime.attachSubPart(meta);
const S32 IMAGE_CONTENT_LENGTH = 6000;
const S32 IMAGE_CONTENT_OFFSET = 200;
const std::string IMAGE_CONTENT_TYPE = std::string("image/j2c");
headers = LLSD::emptyMap();
headers["Content-Length"] = IMAGE_CONTENT_LENGTH;
headers["Content-Type"] = IMAGE_CONTENT_TYPE;
LLMimeIndex image(headers, IMAGE_CONTENT_OFFSET);
mime.attachSubPart(image);
// check what we have
ensure("is multipart", mime.isMultipart());
ensure_equals("multi offset", mime.offset(), MULTI_CONTENT_OFFSET);
ensure_equals(
"multi content length",
mime.contentLength(),
MULTI_CONTENT_LENGTH);
ensure_equals("two attachments", mime.subPartCount(), 2);
LLMimeIndex actual_meta = mime.subPart(0);
ensure_equals(
"meta type", actual_meta.contentType(), META_CONTENT_TYPE);
ensure_equals(
"meta offset", actual_meta.offset(), META_CONTENT_OFFSET);
ensure_equals(
"meta content length",
actual_meta.contentLength(),
META_CONTENT_LENGTH);
LLMimeIndex actual_image = mime.subPart(1);
ensure_equals(
"image type", actual_image.contentType(), IMAGE_CONTENT_TYPE);
ensure_equals(
"image offset", actual_image.offset(), IMAGE_CONTENT_OFFSET);
ensure_equals(
"image content length",
actual_image.contentLength(),
IMAGE_CONTENT_LENGTH);
}
/*
template<> template<>
void mime_index_object_t::test<5>()
{
}
template<> template<>
void mime_index_object_t::test<6>()
{
}
template<> template<>
void mime_index_object_t::test<7>()
{
}
template<> template<>
void mime_index_object_t::test<8>()
{
}
template<> template<>
void mime_index_object_t::test<>()
{
}
*/
}
namespace tut
{
struct mime_parse
{
};
typedef test_group<mime_parse> mime_parse_t;
typedef mime_parse_t::object mime_parse_object_t;
tut::mime_parse_t tut_mime_parse("LLMimeParse");
template<> template<>
void mime_parse_object_t::test<1>()
{
// parse one mime object
const std::string SERIALIZED_MIME("Content-Length: 200\r\nContent-Type: text/plain\r\n\r\naaaaaaaaaaaaaaaaaaaabbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbcccccccccc\r\n");
std::stringstream istr;
istr.str(SERIALIZED_MIME);
LLMimeIndex mime;
LLMimeParser parser;
bool ok = parser.parseIndex(istr, mime);
ensure("Parse successful.", ok);
ensure_equals("content type", mime.contentType(), "text/plain");
ensure_equals("content length", mime.contentLength(), 200);
ensure_equals("offset", mime.offset(), 49);
}
template<> template<>
void mime_parse_object_t::test<2>()
{
// make sure we only parse one.
const std::string SERIALIZED_MIME("Content-Length: 200\r\nContent-Type: text/plain\r\n\r\naaaaaaaaaaaaaaaaaaaabbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbcccccccccc\r\n\r\nContent-Length: 200\r\nContent-Type: text/plain\r\n\r\naaaaaaaaaaaaaaaaaaaabbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbcccccccccc\r\n\r\n");
std::stringstream istr;
istr.str(SERIALIZED_MIME);
LLMimeIndex mime;
LLMimeParser parser;
bool ok = parser.parseIndex(istr, mime);
ensure("Parse successful.", ok);
ensure("not multipart.", !mime.isMultipart());
ensure_equals("content type", mime.contentType(), "text/plain");
ensure_equals("content length", mime.contentLength(), 200);
ensure_equals("offset", mime.offset(), 49);
}
template<> template<>
void mime_parse_object_t::test<3>()
{
// test multi-part and lack of content length for some of it.
/*
Content-Type: multipart/mixed; boundary="segment"rnContent-Length: 148rnrn--segmentrnContent-Type: text/plainrnrnsome datarnrn--segmentrnContent-Type: text/xml; charset=UTF-8rnContent-Length: 22rnrn<llsd><undef /></llsd>rnrn
*/
const std::string SERIALIZED_MIME("Content-Type: multipart/mixed; boundary=\"segment\"\r\nContent-Length: 150\r\n\r\n--segment\r\nContent-Type: text/plain\r\n\r\nsome data\r\n\r\n--segment\r\nContent-Type: text/xml; charset=UTF-8\r\nContent-Length: 22\r\n\r\n<llsd><undef /></llsd>\r\n\r\n");
std::stringstream istr;
istr.str(SERIALIZED_MIME);
LLMimeIndex mime;
LLMimeParser parser;
bool ok = parser.parseIndex(istr, mime);
ensure("Parse successful.", ok);
ensure("is multipart.", mime.isMultipart());
ensure_equals("sub-part count", mime.subPartCount(), 2);
ensure_equals("content length", mime.contentLength(), 150);
ensure_equals("data offset for multipart", mime.offset(), 74);
LLMimeIndex mime_plain(mime.subPart(0));
ensure_equals(
"first part type",
mime_plain.contentType(),
"text/plain");
ensure_equals(
"first part content length not known.",
mime_plain.contentLength(),
-1);
ensure_equals("first part offset", mime_plain.offset(), 113);
LLMimeIndex mime_xml(mime.subPart(1));
ensure_equals(
"second part type",
mime_xml.contentType(),
"text/xml; charset=UTF-8");
ensure_equals(
"second part content length",
mime_xml.contentLength(),
22);
ensure_equals("second part offset", mime_xml.offset(), 198);
}
template<> template<>
void mime_parse_object_t::test<4>()
{
// test multi-part, unquoted separator, and premature eof conditions
/*
Content-Type: multipart/mixed; boundary=segmentrnContent-Length: 220rnrn--segmentrnContent-Type: text/plainrnContent-Length: 55rnrnhow are you today?rnI do not know. I guess I am:n'fine'rnrn--segmentrnContent-Type: text/xml; charset=UTF-8rnContent-Length: 22rnrn<llsd><undef /></llsd>rnrn */
const std::string SERIALIZED_MIME("Content-Type: multipart/mixed; boundary=segment\r\nContent-Length: 220\r\n\r\n--segment\r\nContent-Type: text/plain\r\nContent-Length: 55\r\n\r\nhow are you today?\r\nI do not know. I guess I am:\n'fine'\r\n\r\n--segment\r\nContent-Type: text/xml; charset=UTF-8\r\nContent-Length: 22\r\n\r\n<llsd><undef /></llsd>\r\n\r\n");
std::stringstream istr;
istr.str(SERIALIZED_MIME);
LLMimeIndex mime;
LLMimeParser parser;
bool ok = parser.parseIndex(istr, mime);
ensure("Parse successful.", ok);
ensure("is multipart.", mime.isMultipart());
ensure_equals("sub-part count", mime.subPartCount(), 2);
ensure_equals("content length", mime.contentLength(), 220);
ensure_equals("data offset for multipart", mime.offset(), 72);
LLMimeIndex mime_plain(mime.subPart(0));
ensure_equals(
"first part type",
mime_plain.contentType(),
"text/plain");
ensure_equals(
"first part content length",
mime_plain.contentLength(),
55);
ensure_equals("first part offset", mime_plain.offset(), 131);
LLMimeIndex mime_xml(mime.subPart(1));
ensure_equals(
"second part type",
mime_xml.contentType(),
"text/xml; charset=UTF-8");
ensure_equals(
"second part content length",
mime_xml.contentLength(),
22);
ensure_equals("second part offset", mime_xml.offset(), 262);
}
template<> template<>
void mime_parse_object_t::test<5>()
{
// test multi-part with multiple params
const std::string SERIALIZED_MIME("Content-Type: multipart/mixed; boundary=segment; comment=\"testing multiple params.\"\r\nContent-Length: 220\r\n\r\n--segment\r\nContent-Type: text/plain\r\nContent-Length: 55\r\n\r\nhow are you today?\r\nI do not know. I guess I am:\n'fine'\r\n\r\n--segment\r\nContent-Type: text/xml; charset=UTF-8\r\nContent-Length: 22\r\n\r\n<llsd><undef /></llsd>\r\n\r\n");
std::stringstream istr;
istr.str(SERIALIZED_MIME);
LLMimeIndex mime;
LLMimeParser parser;
bool ok = parser.parseIndex(istr, mime);
ensure("Parse successful.", ok);
ensure("is multipart.", mime.isMultipart());
ensure_equals("sub-part count", mime.subPartCount(), 2);
ensure_equals("content length", mime.contentLength(), 220);
LLMimeIndex mime_plain(mime.subPart(0));
ensure_equals(
"first part type",
mime_plain.contentType(),
"text/plain");
ensure_equals(
"first part content length",
mime_plain.contentLength(),
55);
LLMimeIndex mime_xml(mime.subPart(1));
ensure_equals(
"second part type",
mime_xml.contentType(),
"text/xml; charset=UTF-8");
ensure_equals(
"second part content length",
mime_xml.contentLength(),
22);
}
template<> template<>
void mime_parse_object_t::test<6>()
{
// test multi-part with no specified boundary and eof
/*
Content-Type: multipart/relatedrnContent-Length: 220rnrn--rnContent-Type: text/plainrnContent-Length: 55rnrnhow are you today?rnI do not know. I guess I am:n'fine'rnrn--rnContent-Type: text/xml; charset=UTF-8rnContent-Length: 22rnrn<llsd><undef /></llsd>rnrn
*/
const std::string SERIALIZED_MIME("Content-Type: multipart/related\r\nContent-Length: 500\r\n\r\n--\r\nContent-Type: text/plain\r\nContent-Length: 55\r\n\r\nhow are you today?\r\nI do not know. I guess I am:\n'fine'\r\n\r\n--\r\nContent-Type: text/xml; charset=UTF-8\r\nContent-Length: 22\r\n\r\n<llsd><undef /></llsd>\r\n\r\n");
std::stringstream istr;
istr.str(SERIALIZED_MIME);
LLMimeIndex mime;
LLMimeParser parser;
bool ok = parser.parseIndex(istr, mime);
ensure("Parse successful.", ok);
ensure("is multipart.", mime.isMultipart());
ensure_equals("sub-part count", mime.subPartCount(), 2);
ensure_equals("content length", mime.contentLength(), 500);
ensure_equals("data offset for multipart", mime.offset(), 56);
LLMimeIndex mime_plain(mime.subPart(0));
ensure_equals(
"first part type",
mime_plain.contentType(),
"text/plain");
ensure_equals(
"first part content length",
mime_plain.contentLength(),
55);
ensure_equals("first part offset", mime_plain.offset(), 108);
LLMimeIndex mime_xml(mime.subPart(1));
ensure_equals(
"second part type",
mime_xml.contentType(),
"text/xml; charset=UTF-8");
ensure_equals(
"second part content length",
mime_xml.contentLength(),
22);
ensure_equals("second part offset", mime_xml.offset(), 232);
}
/*
template<> template<>
void mime_parse_object_t::test<>()
{
}
template<> template<>
void mime_parse_object_t::test<>()
{
}
template<> template<>
void mime_parse_object_t::test<>()
{
}
template<> template<>
void mime_parse_object_t::test<>()
{
}
*/
}

View File

@@ -0,0 +1,66 @@
/**
* @file
* @brief
*
* $LicenseInfo:firstyear=2008&license=viewerlgpl$
* Second Life Viewer Source Code
* Copyright (C) 2010, Linden Research, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation;
* version 2.1 of the License only.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
* $/LicenseInfo$
*/
/* Macro Definitions */
#ifndef LL_LLMOCKHTTPCLIENT_H
#define LL_LLMOCKHTTPCLIENT_H
#include "linden_common.h"
#include "llhttpclientinterface.h"
#include <gmock/gmock.h>
class LLMockHTTPClient : public LLHTTPClientInterface
{
public:
MOCK_METHOD2(get, void(const std::string& url, LLCurl::ResponderPtr responder));
MOCK_METHOD3(get, void(const std::string& url, LLCurl::ResponderPtr responder, const LLSD& headers));
MOCK_METHOD3(put, void(const std::string& url, const LLSD& body, LLCurl::ResponderPtr responder));
};
// A helper to match responder types
template<typename T>
struct ResponderType
{
bool operator()(LLCurl::ResponderPtr ptr) const
{
T* p = dynamic_cast<T*>(ptr.get());
return p != NULL;
}
};
inline bool operator==(const LLSD& l, const LLSD& r)
{
std::ostringstream ls, rs;
ls << l;
rs << r;
return ls.str() == rs.str();
}
#endif //LL_LLMOCKHTTPCLIENT_H

View File

@@ -0,0 +1,406 @@
/**
* @file llnamevalue_test.cpp
* @author Adroit
* @date 2007-02
* @brief LLNameValue unit test
*
* $LicenseInfo:firstyear=2007&license=viewerlgpl$
* Second Life Viewer Source Code
* Copyright (C) 2010, Linden Research, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation;
* version 2.1 of the License only.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
* $/LicenseInfo$
*/
#include "linden_common.h"
#include "llsdserialize.h"
#include "../llnamevalue.h"
#include "../test/lltut.h"
#if LL_WINDOWS
// disable unreachable code warnings
#pragma warning(disable: 4702)
#endif
namespace tut
{
struct namevalue_test
{
namevalue_test()
{
}
};
typedef test_group<namevalue_test> namevalue_t;
typedef namevalue_t::object namevalue_object_t;
tut::namevalue_t tut_namevalue("LLNameValue");
template<> template<>
void namevalue_object_t::test<1>()
{
// LLNameValue()
LLNameValue nValue;
ensure("mName should have been NULL", nValue.mName == NULL);
ensure("getTypeEnum failed",nValue.getTypeEnum() == NVT_NULL);
ensure("getClassEnum failed",nValue.getClassEnum() == NVC_NULL);
ensure("getSendtoEnum failed",nValue.getSendtoEnum() == NVS_NULL);
LLNameValue nValue1(" SecondLife ASSET RW SIM 232324343");
}
// LLNameValue(const char* data);
// LLNameValue(const char* name, const char* data, const char* type, const char* nvclass, const char* nvsendto,
// TNameValueCallback nvcb = NULL, void** user_data = NULL);
template<> template<>
void namevalue_object_t::test<2>()
{
LLNameValue nValue(" SecondLife ASSET RW S 232324343");
ensure("mName not set correctly", (0 == strcmp(nValue.mName,"SecondLife")));
ensure("getTypeEnum failed", nValue.getTypeEnum() == NVT_ASSET);
ensure("getClassEnum failed", nValue.getClassEnum() == NVC_READ_WRITE);
ensure("getSendtoEnum failed", nValue.getSendtoEnum() == NVS_SIM);
ensure("getString failed", (0==strcmp(nValue.getAsset(),"232324343")));
ensure("sendToData or sendToViewer failed", !nValue.sendToData() && !nValue.sendToViewer());
LLNameValue nValue1("\n\r SecondLife_1 STRING READ_WRITE SIM 232324343");
ensure("1. mName not set correctly", (0 == strcmp(nValue1.mName,"SecondLife_1")));
ensure("1. getTypeEnum failed", nValue1.getTypeEnum() == NVT_STRING);
ensure("1. getClassEnum failed", nValue1.getClassEnum() == NVC_READ_WRITE);
ensure("1. getSendtoEnum failed", nValue1.getSendtoEnum() == NVS_SIM);
ensure("1. getString failed", (0==strcmp(nValue1.getString(),"232324343")));
ensure("1. sendToData or sendToViewer failed", !nValue1.sendToData() && !nValue1.sendToViewer());
LLNameValue nValue2("SecondLife", "23.5", "F32", "R", "DS");
ensure("2. getTypeEnum failed", nValue2.getTypeEnum() == NVT_F32);
ensure("2. getClassEnum failed", nValue2.getClassEnum() == NVC_READ_ONLY);
ensure("2. getSendtoEnum failed", nValue2.getSendtoEnum() == NVS_DATA_SIM);
ensure("2. getF32 failed", *nValue2.getF32() == 23.5f);
ensure("2. sendToData or sendToViewer failed", nValue2.sendToData() && !nValue2.sendToViewer());
LLNameValue nValue3("SecondLife", "-43456787", "S32", "READ_ONLY", "SIM_SPACE");
ensure("3. getTypeEnum failed", nValue3.getTypeEnum() == NVT_S32);
ensure("3. getClassEnum failed", nValue3.getClassEnum() == NVC_READ_ONLY);
ensure("3. getSendtoEnum failed", nValue3.getSendtoEnum() == NVS_DATA_SIM);
ensure("3. getS32 failed", *nValue3.getS32() == -43456787);
ensure("sendToData or sendToViewer failed", nValue3.sendToData() && !nValue3.sendToViewer());
LLNameValue nValue4("SecondLife", "<1.0, 2.0, 3.0>", "VEC3", "RW", "SV");
LLVector3 llvec4(1.0, 2.0, 3.0);
ensure("4. getTypeEnum failed", nValue4.getTypeEnum() == NVT_VEC3);
ensure("4. getClassEnum failed", nValue4.getClassEnum() == NVC_READ_WRITE);
ensure("4. getSendtoEnum failed", nValue4.getSendtoEnum() == NVS_SIM_VIEWER);
ensure("4. getVec3 failed", *nValue4.getVec3() == llvec4);
ensure("4. sendToData or sendToViewer failed", !nValue4.sendToData() && nValue4.sendToViewer());
LLNameValue nValue5("SecondLife", "-1.0, 2.4, 3", "VEC3", "RW", "SIM_VIEWER");
LLVector3 llvec5(-1.0f, 2.4f, 3);
ensure("5. getTypeEnum failed", nValue5.getTypeEnum() == NVT_VEC3);
ensure("5. getClassEnum failed", nValue5.getClassEnum() == NVC_READ_WRITE);
ensure("5. getSendtoEnum failed", nValue5.getSendtoEnum() == NVS_SIM_VIEWER);
ensure("5. getVec3 failed", *nValue5.getVec3() == llvec5);
ensure("5. sendToData or sendToViewer failed", !nValue5.sendToData() && nValue5.sendToViewer());
LLNameValue nValue6("SecondLife", "89764323", "U32", "RW", "DSV");
ensure("6. getTypeEnum failed", nValue6.getTypeEnum() == NVT_U32);
ensure("6. getClassEnum failed", nValue6.getClassEnum() == NVC_READ_WRITE);
ensure("6. getSendtoEnum failed", nValue6.getSendtoEnum() == NVS_DATA_SIM_VIEWER);
ensure("6. getU32 failed", *nValue6.getU32() == 89764323);
ensure("6. sendToData or sendToViewer failed", nValue6.sendToData() && nValue6.sendToViewer());
LLNameValue nValue7("SecondLife", "89764323323232", "U64", "RW", "SIM_SPACE_VIEWER");
U64 u64_7 = U64L(89764323323232);
ensure("7. getTypeEnum failed", nValue7.getTypeEnum() == NVT_U64);
ensure("7. getClassEnum failed", nValue7.getClassEnum() == NVC_READ_WRITE);
ensure("7. getSendtoEnum failed", nValue7.getSendtoEnum() == NVS_DATA_SIM_VIEWER);
ensure("7. getU32 failed", *nValue7.getU64() == u64_7);
ensure("7. sendToData or sendToViewer failed", nValue7.sendToData() && nValue7.sendToViewer());
}
// LLNameValue(const char* name, const char* data, const char* type, const char* nvclass,
// TNameValueCallback nvcb = NULL, void** user_data = NULL);
template<> template<>
void namevalue_object_t::test<3>()
{
LLNameValue nValue("SecondLife", "232324343", "ASSET", "READ_WRITE");
ensure("mName not set correctly", (0 == strcmp(nValue.mName,"SecondLife")));
ensure("getTypeEnum failed", nValue.getTypeEnum() == NVT_ASSET);
ensure("getClassEnum failed", nValue.getClassEnum() == NVC_READ_WRITE);
ensure("getSendtoEnum failed", nValue.getSendtoEnum() == NVS_SIM);
ensure("getString failed", (0==strcmp(nValue.getAsset(),"232324343")));
LLNameValue nValue1("SecondLife", "232324343", "STRING", "READ_WRITE");
ensure("1. mName not set correctly", (0 == strcmp(nValue1.mName,"SecondLife")));
ensure("1. getTypeEnum failed", nValue1.getTypeEnum() == NVT_STRING);
ensure("1. getClassEnum failed", nValue1.getClassEnum() == NVC_READ_WRITE);
ensure("1. getSendtoEnum failed", nValue1.getSendtoEnum() == NVS_SIM);
ensure("1. getString failed", (0==strcmp(nValue1.getString(),"232324343")));
LLNameValue nValue2("SecondLife", "23.5", "F32", "R");
ensure("2. getTypeEnum failed", nValue2.getTypeEnum() == NVT_F32);
ensure("2. getClassEnum failed", nValue2.getClassEnum() == NVC_READ_ONLY);
ensure("2. getSendtoEnum failed", nValue2.getSendtoEnum() == NVS_SIM);
ensure("2. getF32 failed", *nValue2.getF32() == 23.5f);
LLNameValue nValue3("SecondLife", "-43456787", "S32", "READ_ONLY");
ensure("3. getTypeEnum failed", nValue3.getTypeEnum() == NVT_S32);
ensure("3. getClassEnum failed", nValue3.getClassEnum() == NVC_READ_ONLY);
ensure("3. getSendtoEnum failed", nValue3.getSendtoEnum() == NVS_SIM);
ensure("3. getS32 failed", *nValue3.getS32() == -43456787);
LLNameValue nValue4("SecondLife", "<1.0, 2.0, 3.0>", "VEC3", "RW");
LLVector3 llvec4(1.0, 2.0, 3.0);
ensure("4. getTypeEnum failed", nValue4.getTypeEnum() == NVT_VEC3);
ensure("4. getClassEnum failed", nValue4.getClassEnum() == NVC_READ_WRITE);
ensure("4. getSendtoEnum failed", nValue4.getSendtoEnum() == NVS_SIM);
ensure("4. getVec3 failed", *nValue4.getVec3() == llvec4);
LLNameValue nValue5("SecondLife", "-1.0, 2.4, 3", "VEC3", "RW");
LLVector3 llvec5(-1.0f, 2.4f, 3);
ensure("5. getTypeEnum failed", nValue5.getTypeEnum() == NVT_VEC3);
ensure("5. getClassEnum failed", nValue5.getClassEnum() == NVC_READ_WRITE);
ensure("5. getSendtoEnum failed", nValue5.getSendtoEnum() == NVS_SIM);
ensure("5. getVec3 failed", *nValue5.getVec3() == llvec5);
LLNameValue nValue6("SecondLife", "89764323", "U32", "RW");
ensure("6. getTypeEnum failed", nValue6.getTypeEnum() == NVT_U32);
ensure("6. getClassEnum failed", nValue6.getClassEnum() == NVC_READ_WRITE);
ensure("6. getSendtoEnum failed", nValue6.getSendtoEnum() == NVS_SIM);
ensure("6. getU32 failed", *nValue6.getU32() == 89764323);
LLNameValue nValue7("SecondLife", "89764323323232", "U64", "RW");
U64 u64_7 = U64L(89764323323232);
ensure("7. getTypeEnum failed", nValue7.getTypeEnum() == NVT_U64);
ensure("7. getClassEnum failed", nValue7.getClassEnum() == NVC_READ_WRITE);
ensure("7. getSendtoEnum failed", nValue7.getSendtoEnum() == NVS_SIM);
ensure("7. getU32 failed", *nValue7.getU64() == u64_7);
}
// LLNameValue(const char* name, const char* type, const char* nvclass,
// TNameValueCallback nvcb = NULL, void** user_data = NULL);
template<> template<>
void namevalue_object_t::test<4>()
{
LLNameValue nValue("SecondLife", "STRING", "READ_WRITE");
ensure("mName not set correctly", (0 == strcmp(nValue.mName,"SecondLife")));
ensure("getTypeEnum failed", nValue.getTypeEnum() == NVT_STRING);
ensure("getClassEnum failed", nValue.getClassEnum() == NVC_READ_WRITE);
ensure("getSendtoEnum failed", nValue.getSendtoEnum() == NVS_SIM);
LLNameValue nValue1("SecondLife", "ASSET", "READ_WRITE");
ensure("1. mName not set correctly", (0 == strcmp(nValue1.mName,"SecondLife")));
ensure("1. getTypeEnum for RW failed", nValue1.getTypeEnum() == NVT_ASSET);
ensure("1. getClassEnum for RW failed", nValue1.getClassEnum() == NVC_READ_WRITE);
ensure("1. getSendtoEnum for RW failed", nValue1.getSendtoEnum() == NVS_SIM);
LLNameValue nValue2("SecondLife", "F32", "READ_ONLY");
ensure("2. getTypeEnum failed", nValue2.getTypeEnum() == NVT_F32);
ensure("2. getClassEnum failed", nValue2.getClassEnum() == NVC_READ_ONLY);
ensure("2. getSendtoEnum failed", nValue2.getSendtoEnum() == NVS_SIM);
LLNameValue nValue3("SecondLife", "S32", "READ_ONLY");
ensure("3. getTypeEnum failed", nValue3.getTypeEnum() == NVT_S32);
ensure("3. getClassEnum failed", nValue3.getClassEnum() == NVC_READ_ONLY);
ensure("3. getSendtoEnum failed", nValue3.getSendtoEnum() == NVS_SIM);
LLNameValue nValue4("SecondLife", "VEC3", "READ_WRITE");
ensure("4. getTypeEnum failed", nValue4.getTypeEnum() == NVT_VEC3);
ensure("4. getClassEnum failed", nValue4.getClassEnum() == NVC_READ_WRITE);
ensure("4. getSendtoEnum failed", nValue4.getSendtoEnum() == NVS_SIM);
LLNameValue nValue6("SecondLife", "U32", "READ_WRITE");
ensure("6. getTypeEnum failed", nValue6.getTypeEnum() == NVT_U32);
ensure("6. getClassEnum failed", nValue6.getClassEnum() == NVC_READ_WRITE);
ensure("6. getSendtoEnum failed", nValue6.getSendtoEnum() == NVS_SIM);
LLNameValue nValue7("SecondLife", "U64", "READ_WRITE");
ensure("7. getTypeEnum failed", nValue7.getTypeEnum() == NVT_U64);
ensure("7. getClassEnum failed", nValue7.getClassEnum() == NVC_READ_WRITE);
ensure("7. getSendtoEnum failed", nValue7.getSendtoEnum() == NVS_SIM);
}
template<> template<>
void namevalue_object_t::test<5>()
{
LLNameValue nValue("SecondLife", "This is a test", "STRING", "RW", "SIM");
ensure("getString failed", (0 == strcmp(nValue.getString(),"This is a test")));
}
template<> template<>
void namevalue_object_t::test<6>()
{
LLNameValue nValue("SecondLife", "This is a test", "ASSET", "RW", "S");
ensure("getAsset failed", (0 == strcmp(nValue.getAsset(),"This is a test")));
}
template<> template<>
void namevalue_object_t::test<7>()
{
LLNameValue nValue("SecondLife", "555555", "F32", "RW", "SIM");
ensure("getF32 failed",*nValue.getF32() == 555555.f);
}
template<> template<>
void namevalue_object_t::test<8>()
{
LLNameValue nValue("SecondLife", "-5555", "S32", "RW", "SIM");
ensure("getS32 failed", *nValue.getS32() == -5555);
S32 sVal = 0x7FFFFFFF;
nValue.setS32(sVal);
ensure("getS32 failed", *nValue.getS32() == sVal);
sVal = -0x7FFFFFFF;
nValue.setS32(sVal);
ensure("getS32 failed", *nValue.getS32() == sVal);
sVal = 0;
nValue.setS32(sVal);
ensure("getS32 failed", *nValue.getS32() == sVal);
}
template<> template<>
void namevalue_object_t::test<9>()
{
LLNameValue nValue("SecondLife", "<-3, 2, 1>", "VEC3", "RW", "SIM");
LLVector3 vecExpected(-3, 2, 1);
LLVector3 vec;
nValue.getVec3(vec);
ensure("getVec3 failed", vec == vecExpected);
}
template<> template<>
void namevalue_object_t::test<10>()
{
LLNameValue nValue("SecondLife", "12345678", "U32", "RW", "SIM");
ensure("getU32 failed",*nValue.getU32() == 12345678);
U32 val = 0xFFFFFFFF;
nValue.setU32(val);
ensure("U32 max", *nValue.getU32() == val);
val = 0;
nValue.setU32(val);
ensure("U32 min", *nValue.getU32() == val);
}
template<> template<>
void namevalue_object_t::test<11>()
{
//skip_fail("incomplete support for U64.");
LLNameValue nValue("SecondLife", "44444444444", "U64", "RW", "SIM");
ensure("getU64 failed",*nValue.getU64() == U64L(44444444444));
// there is no LLNameValue::setU64()
}
template<> template<>
void namevalue_object_t::test<12>()
{
//skip_fail("incomplete support for U64.");
LLNameValue nValue("SecondLife U64 RW DSV 44444444444");
std::string ret_str = nValue.printNameValue();
ensure_equals("1:printNameValue failed",ret_str,"SecondLife U64 RW DSV 44444444444");
LLNameValue nValue1(ret_str.c_str());
ensure_equals("Serialization of printNameValue failed", *nValue.getU64(), *nValue1.getU64());
}
template<> template<>
void namevalue_object_t::test<13>()
{
LLNameValue nValue("SecondLife STRING RW DSV 44444444444");
std::string ret_str = nValue.printData();
ensure_equals("1:printData failed",ret_str,"44444444444");
LLNameValue nValue1("SecondLife S32 RW DSV 44444");
ret_str = nValue1.printData();
ensure_equals("2:printData failed",ret_str,"44444");
}
template<> template<>
void namevalue_object_t::test<14>()
{
LLNameValue nValue("SecodLife STRING RW SIM 22222");
std::ostringstream stream1,stream2,stream3, stream4, stream5;
stream1 << nValue;
ensure_equals("STRING << failed",stream1.str(),"22222");
LLNameValue nValue1("SecodLife F32 RW SIM 22222");
stream2 << nValue1;
ensure_equals("F32 << failed",stream2.str(),"22222");
LLNameValue nValue2("SecodLife S32 RW SIM 22222");
stream3<< nValue2;
ensure_equals("S32 << failed",stream3.str(),"22222");
LLNameValue nValue3("SecodLife U32 RW SIM 122222");
stream4<< nValue3;
ensure_equals("U32 << failed",stream4.str(),"122222");
// I don't think we use U64 name value pairs. JC
//skip_fail("incomplete support for U64.");
//LLNameValue nValue4("SecodLife U64 RW SIM 22222");
//stream5<< nValue4;
//ensure("U64 << failed",0 == strcmp((stream5.str()).c_str(),"22222"));
}
template<> template<>
void namevalue_object_t::test<15>()
{
LLNameValue nValue("SecondLife", "This is a test", "ASSET", "R", "S");
ensure("getAsset failed", (0 == strcmp(nValue.getAsset(),"This is a test")));
// this should not have updated as it is read only.
nValue.setAsset("New Value should not be updated");
ensure("setAsset on ReadOnly failed", (0 == strcmp(nValue.getAsset(),"This is a test")));
LLNameValue nValue1("SecondLife", "1234", "U32", "R", "S");
// this should not have updated as it is read only.
nValue1.setU32(4567);
ensure("setU32 on ReadOnly failed", *nValue1.getU32() == 1234);
LLNameValue nValue2("SecondLife", "1234", "S32", "R", "S");
// this should not have updated as it is read only.
nValue2.setS32(4567);
ensure("setS32 on ReadOnly failed", *nValue2.getS32() == 1234);
LLNameValue nValue3("SecondLife", "1234", "F32", "R", "S");
// this should not have updated as it is read only.
nValue3.setF32(4567);
ensure("setF32 on ReadOnly failed", *nValue3.getF32() == 1234);
LLNameValue nValue4("SecondLife", "<1,2,3>", "VEC3", "R", "S");
// this should not have updated as it is read only.
LLVector3 vec(4,5,6);
nValue3.setVec3(vec);
LLVector3 vec1(1,2,3);
ensure("setVec3 on ReadOnly failed", *nValue4.getVec3() == vec1);
// cant test for U64 as no set64 exists nor any operators support U64 type
}
}

View File

@@ -0,0 +1,216 @@
/**
* @file llpartdata_tut.cpp
* @author Adroit
* @date March 2007
* @brief LLPartData and LLPartSysData test cases.
*
* $LicenseInfo:firstyear=2007&license=viewerlgpl$
* Second Life Viewer Source Code
* Copyright (C) 2010, Linden Research, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation;
* version 2.1 of the License only.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
* $/LicenseInfo$
*/
#include "linden_common.h"
#include "lldatapacker.h"
#include "v3math.h"
#include "llsdserialize.h"
#include "message.h"
#include "../llpartdata.h"
#include "../test/lltut.h"
namespace tut
{
struct partdata_test
{
};
typedef test_group<partdata_test> partdata_test_t;
typedef partdata_test_t::object partdata_test_object_t;
tut::partdata_test_t tut_partdata_test("LLPartData");
template<> template<>
void partdata_test_object_t::test<1>()
{
LLPartData llpdata,llpdata1;
U8 pkbuf[128];
llpdata.setFlags(LLPartData::LL_PART_INTERP_COLOR_MASK | LLPartData::LL_PART_INTERP_SCALE_MASK |
LLPartData::LL_PART_BOUNCE_MASK | LLPartData::LL_PART_WIND_MASK | LLPartData::LL_PART_FOLLOW_SRC_MASK |
LLPartData::LL_PART_FOLLOW_VELOCITY_MASK | LLPartData::LL_PART_TARGET_POS_MASK | LLPartData::LL_PART_TARGET_LINEAR_MASK |
LLPartData::LL_PART_EMISSIVE_MASK | LLPartData::LL_PART_BEAM_MASK | LLPartData::LL_PART_DEAD_MASK);
llpdata.setMaxAge(29.3f);
LLVector3 llvec1(1.0f, .5f, .25f);
llpdata.setStartColor(llvec1);
llpdata.setStartAlpha(.7f);
LLVector3 llvec2(.2f, .3f, 1.0f);
llpdata.setEndColor(llvec2);
llpdata.setEndAlpha(1.0f);
llpdata.setStartScale(3.23f, 4.0f);
llpdata.setEndScale(2.4678f, 1.0f);
LLDataPackerBinaryBuffer dp((U8*)pkbuf, 128);
llpdata.pack(dp);
S32 cur_size = dp.getCurrentSize();
LLDataPackerBinaryBuffer dp1((U8*)pkbuf, cur_size);
llpdata1.unpack(dp1);
ensure("1.mFlags values are different after unpacking", llpdata1.mFlags == llpdata.mFlags);
ensure_approximately_equals("2.mMaxAge values are different after unpacking", llpdata1.mMaxAge, llpdata.mMaxAge, 8);
ensure_approximately_equals("3.mStartColor[0] values are different after unpacking", llpdata1.mStartColor.mV[0], llpdata.mStartColor.mV[0], 8);
ensure_approximately_equals("4.mStartColor[1] values are different after unpacking", llpdata1.mStartColor.mV[1], llpdata.mStartColor.mV[1], 8);
ensure_approximately_equals("5.mStartColor[2] values are different after unpacking", llpdata1.mStartColor.mV[2], llpdata.mStartColor.mV[2], 8);
ensure_approximately_equals("6.mStartColor[3] values are different after unpacking", llpdata1.mStartColor.mV[3], llpdata.mStartColor.mV[3], 8);
ensure_approximately_equals("7.mEndColor[0] values are different after unpacking", llpdata1.mEndColor.mV[0], llpdata.mEndColor.mV[0], 8);
ensure_approximately_equals("8.mEndColor[1] values are different after unpacking", llpdata1.mEndColor.mV[1], llpdata.mEndColor.mV[1], 8);
ensure_approximately_equals("9.mEndColor[2] values are different after unpacking", llpdata1.mEndColor.mV[2], llpdata.mEndColor.mV[2], 8);
ensure_approximately_equals("10.mEndColor[2] values are different after unpacking", llpdata1.mEndColor.mV[3], llpdata.mEndColor.mV[3], 8);
ensure_approximately_equals("11.mStartScale[0] values are different after unpacking", llpdata1.mStartScale.mV[0], llpdata.mStartScale.mV[0], 5);
ensure_approximately_equals("12.mStartScale[1] values are different after unpacking", llpdata1.mStartScale.mV[1], llpdata.mStartScale.mV[1], 5);
ensure_approximately_equals("13.mEndScale[0] values are different after unpacking", llpdata1.mEndScale.mV[0], llpdata.mEndScale.mV[0], 5);
ensure_approximately_equals("14.mEndScale[1] values are different after unpacking", llpdata1.mEndScale.mV[1], llpdata.mEndScale.mV[1], 5);
}
template<> template<>
void partdata_test_object_t::test<2>()
{
LLPartData llpdata,llpdata1;
llpdata.setFlags(LLPartData::LL_PART_INTERP_COLOR_MASK | LLPartData::LL_PART_INTERP_SCALE_MASK |
LLPartData::LL_PART_BOUNCE_MASK | LLPartData::LL_PART_WIND_MASK | LLPartData::LL_PART_FOLLOW_SRC_MASK |
LLPartData::LL_PART_FOLLOW_VELOCITY_MASK | LLPartData::LL_PART_TARGET_POS_MASK | LLPartData::LL_PART_TARGET_LINEAR_MASK |
LLPartData::LL_PART_EMISSIVE_MASK | LLPartData::LL_PART_BEAM_MASK | LLPartData::LL_PART_DEAD_MASK);
llpdata.setMaxAge(29.3f);
LLVector3 llvec1(1.0f, .5f, .25f);
llpdata.setStartColor(llvec1);
llpdata.setStartAlpha(.7f);
LLVector3 llvec2(.2f, .3f, 1.0f);
llpdata.setEndColor(llvec2);
llpdata.setEndAlpha(1.0f);
llpdata.setStartScale(3.23f, 4.0f);
llpdata.setEndScale(2.4678f, 1.0f);
LLSD llsd = llpdata.asLLSD();
llpdata1.fromLLSD(llsd);
ensure("1.mFlags values are different after unpacking", llpdata1.mFlags == llpdata.mFlags);
ensure_approximately_equals("2.mMaxAge values are different after unpacking", llpdata1.mMaxAge, llpdata.mMaxAge, 8);
ensure_approximately_equals("3.mStartColor[0] values are different after unpacking", llpdata1.mStartColor.mV[0], llpdata.mStartColor.mV[0], 8);
ensure_approximately_equals("4.mStartColor[1] values are different after unpacking", llpdata1.mStartColor.mV[1], llpdata.mStartColor.mV[1], 8);
ensure_approximately_equals("5.mStartColor[2] values are different after unpacking", llpdata1.mStartColor.mV[2], llpdata.mStartColor.mV[2], 8);
ensure_approximately_equals("6.mStartColor[3] values are different after unpacking", llpdata1.mStartColor.mV[3], llpdata.mStartColor.mV[3], 8);
ensure_approximately_equals("7.mEndColor[0] values are different after unpacking", llpdata1.mEndColor.mV[0], llpdata.mEndColor.mV[0], 8);
ensure_approximately_equals("8.mEndColor[1] values are different after unpacking", llpdata1.mEndColor.mV[1], llpdata.mEndColor.mV[1], 8);
ensure_approximately_equals("9.mEndColor[2] values are different after unpacking", llpdata1.mEndColor.mV[2], llpdata.mEndColor.mV[2], 8);
ensure_approximately_equals("10.mEndColor[2] values are different after unpacking", llpdata1.mEndColor.mV[3], llpdata.mEndColor.mV[3], 8);
ensure_approximately_equals("11.mStartScale[0] values are different after unpacking", llpdata1.mStartScale.mV[0], llpdata.mStartScale.mV[0], 5);
ensure_approximately_equals("12.mStartScale[1] values are different after unpacking", llpdata1.mStartScale.mV[1], llpdata.mStartScale.mV[1], 5);
ensure_approximately_equals("13.mEndScale[0] values are different after unpacking", llpdata1.mEndScale.mV[0], llpdata.mEndScale.mV[0], 5);
ensure_approximately_equals("14.mEndScale[1] values are different after unpacking", llpdata1.mEndScale.mV[1], llpdata.mEndScale.mV[1], 5);
}
//*********llpartsysdata***********
template<> template<>
void partdata_test_object_t::test<3>()
{
LLPartSysData llpsysdata, llpsysdata1;
U8 pkbuf[256];
llpsysdata.setBurstSpeedMin(33.33f);
ensure("1.mBurstSpeedMin coudnt be set", 33.33f == llpsysdata.mBurstSpeedMin);
llpsysdata.setBurstSpeedMax(44.44f);
ensure("2.mBurstSpeedMax coudnt be set", 44.44f == llpsysdata.mBurstSpeedMax);
llpsysdata.setBurstRadius(45.55f);
ensure("3.mBurstRadius coudnt be set", 45.55f == llpsysdata.mBurstRadius);
LLVector3 llvec(44.44f, 111.11f, -40.4f);
llpsysdata.setPartAccel(llvec);
llpsysdata.mCRC = 0xFFFFFFFF;
llpsysdata.mFlags = 0x20;
llpsysdata.mPattern = LLPartSysData::LL_PART_SRC_PATTERN_ANGLE_CONE_EMPTY;
llpsysdata.mMaxAge = 99.99f;
llpsysdata.mStartAge = 18.5f;
llpsysdata.mInnerAngle = 4.234f;
llpsysdata.mOuterAngle = 7.123f;
llpsysdata.mBurstRate = 245.53f;
llpsysdata.mBurstPartCount = 0xFF;
llpsysdata.mAngularVelocity = llvec;
llpsysdata.mPartImageID.generate();
llpsysdata.mTargetUUID.generate();
LLDataPackerBinaryBuffer dp((U8*)pkbuf, 256);
llpsysdata.pack(dp);
S32 cur_size = dp.getCurrentSize();
LLDataPackerBinaryBuffer dp1((U8*)pkbuf, cur_size);
llpsysdata1.unpack(dp1);
ensure("1.mCRC's not equal", llpsysdata.mCRC == llpsysdata1.mCRC);
ensure("2.mFlags's not equal", llpsysdata.mFlags == llpsysdata1.mFlags);
ensure("3.mPattern's not equal", llpsysdata.mPattern == llpsysdata1.mPattern);
ensure_approximately_equals("4.mMaxAge's not equal", llpsysdata.mMaxAge , llpsysdata1.mMaxAge, 8);
ensure_approximately_equals("5.mStartAge's not equal", llpsysdata.mStartAge, llpsysdata1.mStartAge, 8);
ensure_approximately_equals("6.mOuterAngle's not equal", llpsysdata.mOuterAngle, llpsysdata1.mOuterAngle, 5);
ensure_approximately_equals("7.mInnerAngles's not equal", llpsysdata.mInnerAngle, llpsysdata1.mInnerAngle, 5);
ensure_approximately_equals("8.mBurstRate's not equal", llpsysdata.mBurstRate, llpsysdata1.mBurstRate, 8);
ensure("9.mBurstPartCount's not equal", llpsysdata.mBurstPartCount == llpsysdata1.mBurstPartCount);
ensure_approximately_equals("10.mBurstSpeedMin's not equal", llpsysdata.mBurstSpeedMin, llpsysdata1.mBurstSpeedMin, 8);
ensure_approximately_equals("11.mBurstSpeedMax's not equal", llpsysdata.mBurstSpeedMax, llpsysdata1.mBurstSpeedMax, 8);
ensure_approximately_equals("12.mAngularVelocity's not equal", llpsysdata.mAngularVelocity.mV[0], llpsysdata1.mAngularVelocity.mV[0], 7);
ensure_approximately_equals("13.mAngularVelocity's not equal", llpsysdata.mAngularVelocity.mV[1], llpsysdata1.mAngularVelocity.mV[1], 7);
ensure_approximately_equals("14.mAngularVelocity's not equal", llpsysdata.mAngularVelocity.mV[2], llpsysdata1.mAngularVelocity.mV[2], 7);
ensure_approximately_equals("15.mPartAccel's not equal", llpsysdata.mPartAccel.mV[0], llpsysdata1.mPartAccel.mV[0], 7);
ensure_approximately_equals("16.mPartAccel's not equal", llpsysdata.mPartAccel.mV[1], llpsysdata1.mPartAccel.mV[1], 7);
ensure_approximately_equals("17.mPartAccel's not equal", llpsysdata.mPartAccel.mV[2], llpsysdata1.mPartAccel.mV[2], 7);
ensure("18.mPartImageID's not equal", llpsysdata.mPartImageID == llpsysdata1.mPartImageID);
ensure("19.mTargetUUID's not equal", llpsysdata.mTargetUUID == llpsysdata1.mTargetUUID);
ensure_approximately_equals("20.mBurstRadius's not equal", llpsysdata.mBurstRadius, llpsysdata1.mBurstRadius, 8);
}
}

View File

@@ -0,0 +1,108 @@
/**
* @file
* @brief
*
* $LicenseInfo:firstyear=2008&license=viewerlgpl$
* Second Life Viewer Source Code
* Copyright (C) 2010, Linden Research, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation;
* version 2.1 of the License only.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
* $/LicenseInfo$
*/
#include "linden_common.h"
#include "../test/lltut.h"
#include "llregionpresenceverifier.h"
#include "llcurl_stub.cpp"
#include "llhost.cpp"
#include "net.cpp"
#include "lltesthttpclientadapter.cpp"
class LLTestResponse : public LLRegionPresenceVerifier::Response
{
public:
virtual bool checkValidity(const LLSD& content) const
{
return true;
}
virtual void onRegionVerified(const LLSD& region_details)
{
}
virtual void onRegionVerificationFailed()
{
}
virtual LLHTTPClientInterface& getHttpClient()
{
return mHttpInterface;
}
LLTestHTTPClientAdapter mHttpInterface;
};
namespace tut
{
struct LLRegionPresenceVerifierData
{
LLRegionPresenceVerifierData() :
mResponse(new LLTestResponse()),
mResponder("", LLRegionPresenceVerifier::ResponsePtr(mResponse),
LLSD(), 3)
{
}
LLTestResponse* mResponse;
LLRegionPresenceVerifier::VerifiedDestinationResponder mResponder;
};
typedef test_group<LLRegionPresenceVerifierData> factory;
typedef factory::object object;
}
namespace
{
tut::factory tf("LLRegionPresenceVerifier");
}
namespace tut
{
// Test that VerifiedDestinationResponder does retry
// on error when shouldRetry returns true.
template<> template<>
void object::test<1>()
{
mResponder.error(500, "Internal server error");
ensure_equals(mResponse->mHttpInterface.mGetUrl.size(), 1);
}
// Test that VerifiedDestinationResponder only retries
// on error until shouldRetry returns false.
template<> template<>
void object::test<2>()
{
mResponder.error(500, "Internal server error");
mResponder.error(500, "Internal server error");
mResponder.error(500, "Internal server error");
mResponder.error(500, "Internal server error");
ensure_equals(mResponse->mHttpInterface.mGetUrl.size(), 3);
}
}

View File

@@ -0,0 +1,158 @@
/**
* @file llsdmessage_test.cpp
* @author Nat Goodspeed
* @date 2008-12-22
* @brief Test of llsdmessage.h
*
* $LicenseInfo:firstyear=2008&license=viewerlgpl$
* Second Life Viewer Source Code
* Copyright (C) 2010, Linden Research, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation;
* version 2.1 of the License only.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
* $/LicenseInfo$
*/
#if LL_WINDOWS
#pragma warning (disable : 4675) // "resolved by ADL" -- just as I want!
#endif
// Precompiled header
#include "linden_common.h"
// associated header
#include "llsdmessage.h"
// STL headers
#include <iostream>
// std headers
#include <stdexcept>
#include <typeinfo>
// external library headers
// other Linden headers
#include "../test/lltut.h"
#include "llsdserialize.h"
#include "llevents.h"
#include "stringize.h"
#include "llhost.h"
#include "tests/networkio.h"
#include "tests/commtest.h"
/*****************************************************************************
* TUT
*****************************************************************************/
namespace tut
{
struct llsdmessage_data: public commtest_data
{
LLEventPump& httpPump;
llsdmessage_data():
httpPump(pumps.obtain("LLHTTPClient"))
{
LLCurl::initClass();
LLSDMessage::link();
}
};
typedef test_group<llsdmessage_data> llsdmessage_group;
typedef llsdmessage_group::object llsdmessage_object;
llsdmessage_group llsdmgr("llsdmessage");
template<> template<>
void llsdmessage_object::test<1>()
{
bool threw = false;
// This should fail...
try
{
LLSDMessage localListener;
}
catch (const LLEventPump::DupPumpName&)
{
threw = true;
}
catch (const std::runtime_error& ex)
{
// This clause is because on Linux, on the viewer side, for this
// one test program (though not others!), the
// LLEventPump::DupPumpName exception isn't caught by the clause
// above. Warn the user...
std::cerr << "Failed to catch " << typeid(ex).name() << std::endl;
// But if the expected exception was thrown, allow the test to
// succeed anyway. Not sure how else to handle this odd case.
if (std::string(typeid(ex).name()) == typeid(LLEventPump::DupPumpName).name())
{
threw = true;
}
else
{
// We don't even recognize this exception. Let it propagate
// out to TUT to fail the test.
throw;
}
}
catch (...)
{
std::cerr << "Utterly failed to catch expected exception!" << std::endl;
// This case is full of fail. We HAVE to address it.
throw;
}
ensure("second LLSDMessage should throw", threw);
}
template<> template<>
void llsdmessage_object::test<2>()
{
LLSD request, body;
body["data"] = "yes";
request["payload"] = body;
request["reply"] = replyPump.getName();
request["error"] = errorPump.getName();
bool threw = false;
try
{
httpPump.post(request);
}
catch (const LLSDMessage::ArgError&)
{
threw = true;
}
ensure("missing URL", threw);
}
template<> template<>
void llsdmessage_object::test<3>()
{
LLSD request, body;
body["data"] = "yes";
request["url"] = server + "got-message";
request["payload"] = body;
request["reply"] = replyPump.getName();
request["error"] = errorPump.getName();
httpPump.post(request);
ensure("got response", netio.pump());
ensure("success response", success);
ensure_equals(result.asString(), "success");
body["status"] = 499;
body["reason"] = "custom error message";
request["url"] = server + "fail";
request["payload"] = body;
httpPump.post(request);
ensure("got response", netio.pump());
ensure("failure response", ! success);
ensure_equals(result["status"].asInteger(), body["status"].asInteger());
ensure_equals(result["reason"].asString(), body["reason"].asString());
}
} // namespace tut

View File

@@ -0,0 +1,58 @@
/**
* @file llxfer_test.cpp
* @author Moss
* @date 2007-04-17
*
* $LicenseInfo:firstyear=2007&license=viewerlgpl$
* Second Life Viewer Source Code
* Copyright (C) 2010, Linden Research, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation;
* version 2.1 of the License only.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
* $/LicenseInfo$
*/
#include "linden_common.h"
#include "../llxfer_file.h"
#include "../test/lltut.h"
namespace tut
{
struct llxfer_data
{
};
typedef test_group<llxfer_data> llxfer_test;
typedef llxfer_test::object llxfer_object;
tut::llxfer_test llxfer("LLXferFile");
template<> template<>
void llxfer_object::test<1>()
{
// test that we handle an oversized filename correctly.
std::string oversized_filename;
U32 i;
for (i=0; i<LL_MAX_PATH*2; ++i) // create oversized filename
{
oversized_filename += 'X';
}
LLXfer_File xff(oversized_filename, FALSE, 1);
ensure("oversized local_filename nul-terminated",
xff.getFileName().length() < LL_MAX_PATH);
}
}

View File

@@ -0,0 +1,262 @@
#!/usr/bin/env python
"""\
@file testrunner.py
@author Nat Goodspeed
@date 2009-03-20
@brief Utilities for writing wrapper scripts for ADD_COMM_BUILD_TEST unit tests
$LicenseInfo:firstyear=2009&license=viewerlgpl$
Second Life Viewer Source Code
Copyright (C) 2010, Linden Research, Inc.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation;
version 2.1 of the License only.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
$/LicenseInfo$
"""
from __future__ import with_statement
import os
import sys
import re
import errno
import socket
VERBOSE = os.environ.get("INTEGRATION_TEST_VERBOSE", "1") # default to verbose
# Support usage such as INTEGRATION_TEST_VERBOSE=off -- distressing to user if
# that construct actually turns on verbosity...
VERBOSE = not re.match(r"(0|off|false|quiet)$", VERBOSE, re.IGNORECASE)
if VERBOSE:
def debug(fmt, *args):
print fmt % args
sys.stdout.flush()
else:
debug = lambda *args: None
def freeport(portlist, expr):
"""
Find a free server port to use. Specifically, evaluate 'expr' (a
callable(port)) until it stops raising EADDRINUSE exception.
Pass:
portlist: an iterable (e.g. xrange()) of ports to try. If you exhaust the
range, freeport() lets the socket.error exception propagate. If you want
unbounded, you could pass itertools.count(baseport), though of course in
practice the ceiling is 2^16-1 anyway. But it seems prudent to constrain
the range much more sharply: if we're iterating an absurd number of times,
probably something else is wrong.
expr: a callable accepting a port number, specifically one of the items
from portlist. If calling that callable raises socket.error with
EADDRINUSE, freeport() retrieves the next item from portlist and retries.
Returns: (expr(port), port)
port: the value from portlist for which expr(port) succeeded
Raises:
Any exception raised by expr(port) other than EADDRINUSE.
socket.error if, for every item from portlist, expr(port) raises
socket.error. The exception you see is the one from the last item in
portlist.
StopIteration if portlist is completely empty.
Example:
class Server(HTTPServer):
# If you use BaseHTTPServer.HTTPServer, turning off this flag is
# essential for proper operation of freeport()!
allow_reuse_address = False
# ...
server, port = freeport(xrange(8000, 8010),
lambda port: Server(("localhost", port),
MyRequestHandler))
# pass 'port' to client code
# call server.serve_forever()
"""
try:
# If portlist is completely empty, let StopIteration propagate: that's an
# error because we can't return meaningful values. We have no 'port',
# therefore no 'expr(port)'.
portiter = iter(portlist)
port = portiter.next()
while True:
try:
# If this value of port works, return as promised.
value = expr(port)
except socket.error, err:
# Anything other than 'Address already in use', propagate
if err.args[0] != errno.EADDRINUSE:
raise
# Here we want the next port from portiter. But on StopIteration,
# we want to raise the original exception rather than
# StopIteration. So save the original exc_info().
type, value, tb = sys.exc_info()
try:
try:
port = portiter.next()
except StopIteration:
raise type, value, tb
finally:
# Clean up local traceback, see docs for sys.exc_info()
del tb
else:
debug("freeport() returning %s on port %s", value, port)
return value, port
# Recap of the control flow above:
# If expr(port) doesn't raise, return as promised.
# If expr(port) raises anything but EADDRINUSE, propagate that
# exception.
# If portiter.next() raises StopIteration -- that is, if the port
# value we just passed to expr(port) was the last available -- reraise
# the EADDRINUSE exception.
# If we've actually arrived at this point, portiter.next() delivered a
# new port value. Loop back to pass that to expr(port).
except Exception, err:
debug("*** freeport() raising %s: %s", err.__class__.__name__, err)
raise
def run(*args, **kwds):
"""All positional arguments collectively form a command line, executed as
a synchronous child process.
In addition, pass server=new_thread_instance as an explicit keyword (to
differentiate it from an additional command-line argument).
new_thread_instance should be an instantiated but not yet started Thread
subclass instance, e.g.:
run("python", "-c", 'print "Hello, world!"', server=TestHTTPServer(name="httpd"))
"""
# If there's no server= keyword arg, don't start a server thread: simply
# run a child process.
try:
thread = kwds.pop("server")
except KeyError:
pass
else:
# Start server thread. Note that this and all other comm server
# threads should be daemon threads: we'll let them run "forever,"
# confident that the whole process will terminate when the main thread
# terminates, which will be when the child process terminates.
thread.setDaemon(True)
thread.start()
# choice of os.spawnv():
# - [v vs. l] pass a list of args vs. individual arguments,
# - [no p] don't use the PATH because we specifically want to invoke the
# executable passed as our first arg,
# - [no e] child should inherit this process's environment.
debug("Running %s...", " ".join(args))
rc = os.spawnv(os.P_WAIT, args[0], args)
debug("%s returned %s", args[0], rc)
return rc
# ****************************************************************************
# test code -- manual at this point, see SWAT-564
# ****************************************************************************
def test_freeport():
# ------------------------------- Helpers --------------------------------
from contextlib import contextmanager
# helper Context Manager for expecting an exception
# with exc(SomeError):
# raise SomeError()
# raises AssertionError otherwise.
@contextmanager
def exc(exception_class, *args):
try:
yield
except exception_class, err:
for i, expected_arg in enumerate(args):
assert expected_arg == err.args[i], \
"Raised %s, but args[%s] is %r instead of %r" % \
(err.__class__.__name__, i, err.args[i], expected_arg)
print "Caught expected exception %s(%s)" % \
(err.__class__.__name__, ', '.join(repr(arg) for arg in err.args))
else:
assert False, "Failed to raise " + exception_class.__class__.__name__
# helper to raise specified exception
def raiser(exception):
raise exception
# the usual
def assert_equals(a, b):
assert a == b, "%r != %r" % (a, b)
# ------------------------ Sanity check the above ------------------------
class SomeError(Exception): pass
# Without extra args, accept any err.args value
with exc(SomeError):
raiser(SomeError("abc"))
# With extra args, accept only the specified value
with exc(SomeError, "abc"):
raiser(SomeError("abc"))
with exc(AssertionError):
with exc(SomeError, "abc"):
raiser(SomeError("def"))
with exc(AssertionError):
with exc(socket.error, errno.EADDRINUSE):
raiser(socket.error(errno.ECONNREFUSED, 'Connection refused'))
# ----------- freeport() without engaging socket functionality -----------
# If portlist is empty, freeport() raises StopIteration.
with exc(StopIteration):
freeport([], None)
assert_equals(freeport([17], str), ("17", 17))
# This is the magic exception that should prompt us to retry
inuse = socket.error(errno.EADDRINUSE, 'Address already in use')
# Get the iterator to our ports list so we can check later if we've used all
ports = iter(xrange(5))
with exc(socket.error, errno.EADDRINUSE):
freeport(ports, lambda port: raiser(inuse))
# did we entirely exhaust 'ports'?
with exc(StopIteration):
ports.next()
ports = iter(xrange(2))
# Any exception but EADDRINUSE should quit immediately
with exc(SomeError):
freeport(ports, lambda port: raiser(SomeError()))
assert_equals(ports.next(), 1)
# ----------- freeport() with platform-dependent socket stuff ------------
# This is what we should've had unit tests to begin with (see CHOP-661).
def newbind(port):
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.bind(('127.0.0.1', port))
return sock
bound0, port0 = freeport(xrange(7777, 7780), newbind)
assert_equals(port0, 7777)
bound1, port1 = freeport(xrange(7777, 7780), newbind)
assert_equals(port1, 7778)
bound2, port2 = freeport(xrange(7777, 7780), newbind)
assert_equals(port2, 7779)
with exc(socket.error, errno.EADDRINUSE):
bound3, port3 = freeport(xrange(7777, 7780), newbind)
if __name__ == "__main__":
test_freeport()