aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/linden
diff options
context:
space:
mode:
Diffstat (limited to 'linden')
-rw-r--r--linden/etc/message.xml24
-rw-r--r--linden/indra/lib/python/indra/ipc/llsdhttp.py2
-rw-r--r--linden/indra/lib/python/indra/ipc/mysql_pool.py23
-rw-r--r--linden/indra/lib/python/indra/ipc/servicebuilder.py29
-rw-r--r--linden/indra/lib/python/indra/ipc/siesta.py4
-rw-r--r--linden/indra/lib/python/indra/util/llmanifest.py3
-rw-r--r--linden/indra/lib/python/indra/util/llversion.py5
-rw-r--r--linden/indra/lib/python/indra/util/named_query.py37
-rw-r--r--linden/indra/llcommon/llstat.cpp562
-rw-r--r--linden/indra/llcommon/llstat.h142
-rw-r--r--linden/indra/llmath/llmodularmath.h57
-rw-r--r--linden/indra/llmessage/llcircuit.cpp11
-rw-r--r--linden/indra/llmessage/llcircuit.h8
-rw-r--r--linden/indra/llmessage/llcurl.cpp6
-rw-r--r--linden/indra/llmessage/llhttpassetstorage.cpp4
-rw-r--r--linden/indra/llmessage/llhttpclient.cpp112
-rw-r--r--linden/indra/llmessage/llhttpclient.h50
-rw-r--r--linden/indra/llmessage/lliohttpserver.cpp7
-rw-r--r--linden/indra/llmessage/llmail.cpp34
-rw-r--r--linden/indra/llmessage/llmail.h61
-rw-r--r--linden/indra/llmessage/llmessagetemplate.cpp22
-rw-r--r--linden/indra/llmessage/llmessagetemplate.h12
-rw-r--r--linden/indra/llmessage/llmessagethrottle.cpp4
-rw-r--r--linden/indra/llmessage/llnamevalue.cpp4
-rw-r--r--linden/indra/llmessage/llnamevalue.h4
-rw-r--r--linden/indra/llmessage/llpumpio.cpp6
-rw-r--r--linden/indra/llmessage/llregionflags.h6
-rw-r--r--linden/indra/llmessage/message.cpp32
-rw-r--r--linden/indra/llmessage/message.h16
29 files changed, 1075 insertions, 212 deletions
diff --git a/linden/etc/message.xml b/linden/etc/message.xml
index 0695d05..d833074 100644
--- a/linden/etc/message.xml
+++ b/linden/etc/message.xml
@@ -441,6 +441,30 @@
441 <boolean>true</boolean> 441 <boolean>true</boolean>
442 </map> 442 </map>
443 443
444 <key>EnableSimulator</key>
445 <map>
446 <key>flavor</key>
447 <string>llsd</string>
448 <key>trusted-sender</key>
449 <boolean>true</boolean>
450 </map>
451
452 <key>TeleportFinish</key>
453 <map>
454 <key>flavor</key>
455 <string>llsd</string>
456 <key>trusted-sender</key>
457 <boolean>true</boolean>
458 </map>
459
460 <key>CrossedRegion</key>
461 <map>
462 <key>flavor</key>
463 <string>llsd</string>
464 <key>trusted-sender</key>
465 <boolean>true</boolean>
466 </map>
467
444 <!-- UDPDeprecated Messages --> 468 <!-- UDPDeprecated Messages -->
445 <key>ScriptRunningReply</key> 469 <key>ScriptRunningReply</key>
446 <map> 470 <map>
diff --git a/linden/indra/lib/python/indra/ipc/llsdhttp.py b/linden/indra/lib/python/indra/ipc/llsdhttp.py
index 1cf1146..ed64899 100644
--- a/linden/indra/lib/python/indra/ipc/llsdhttp.py
+++ b/linden/indra/lib/python/indra/ipc/llsdhttp.py
@@ -51,6 +51,8 @@ request_ = suite.request_
51# import every httpc error exception into our namespace for convenience 51# import every httpc error exception into our namespace for convenience
52for x in httpc.status_to_error_map.itervalues(): 52for x in httpc.status_to_error_map.itervalues():
53 globals()[x.__name__] = x 53 globals()[x.__name__] = x
54ConnectionError = httpc.ConnectionError
55Retriable = httpc.Retriable
54 56
55for x in (httpc.ConnectionError,): 57for x in (httpc.ConnectionError,):
56 globals()[x.__name__] = x 58 globals()[x.__name__] = x
diff --git a/linden/indra/lib/python/indra/ipc/mysql_pool.py b/linden/indra/lib/python/indra/ipc/mysql_pool.py
index 507b185..25a66cf 100644
--- a/linden/indra/lib/python/indra/ipc/mysql_pool.py
+++ b/linden/indra/lib/python/indra/ipc/mysql_pool.py
@@ -30,8 +30,10 @@ import MySQLdb
30from eventlet import db_pool 30from eventlet import db_pool
31 31
32class DatabaseConnector(db_pool.DatabaseConnector): 32class DatabaseConnector(db_pool.DatabaseConnector):
33 def __init__(self, credentials, min_size = 0, max_size = 4, *args, **kwargs): 33 def __init__(self, credentials, *args, **kwargs):
34 super(DatabaseConnector, self).__init__(MySQLdb, credentials, min_size, max_size, conn_pool=db_pool.ConnectionPool, *args, **kwargs) 34 super(DatabaseConnector, self).__init__(MySQLdb, credentials,
35 conn_pool=db_pool.ConnectionPool,
36 *args, **kwargs)
35 37
36 # get is extended relative to eventlet.db_pool to accept a port argument 38 # get is extended relative to eventlet.db_pool to accept a port argument
37 def get(self, host, dbname, port=3306): 39 def get(self, host, dbname, port=3306):
@@ -42,7 +44,7 @@ class DatabaseConnector(db_pool.DatabaseConnector):
42 new_kwargs['host'] = host 44 new_kwargs['host'] = host
43 new_kwargs['port'] = port 45 new_kwargs['port'] = port
44 new_kwargs.update(self.credentials_for(host)) 46 new_kwargs.update(self.credentials_for(host))
45 dbpool = ConnectionPool(self._min_size, self._max_size, *self._args, **new_kwargs) 47 dbpool = ConnectionPool(*self._args, **new_kwargs)
46 self._databases[key] = dbpool 48 self._databases[key] = dbpool
47 49
48 return self._databases[key] 50 return self._databases[key]
@@ -51,8 +53,8 @@ class ConnectionPool(db_pool.TpooledConnectionPool):
51 """A pool which gives out saranwrapped MySQLdb connections from a pool 53 """A pool which gives out saranwrapped MySQLdb connections from a pool
52 """ 54 """
53 55
54 def __init__(self, min_size = 0, max_size = 4, *args, **kwargs): 56 def __init__(self, *args, **kwargs):
55 super(ConnectionPool, self).__init__(MySQLdb, min_size, max_size, *args, **kwargs) 57 super(ConnectionPool, self).__init__(MySQLdb, *args, **kwargs)
56 58
57 def get(self): 59 def get(self):
58 conn = super(ConnectionPool, self).get() 60 conn = super(ConnectionPool, self).get()
@@ -77,14 +79,3 @@ class ConnectionPool(db_pool.TpooledConnectionPool):
77 conn.connection_parameters = converted_kwargs 79 conn.connection_parameters = converted_kwargs
78 return conn 80 return conn
79 81
80 def clear(self):
81 """ Close all connections that this pool still holds a reference to, leaving it empty."""
82 for conn in self.free_items:
83 try:
84 conn.close()
85 except:
86 pass # even if stuff happens here, we still want to at least try to close all the other connections
87 self.free_items.clear()
88
89 def __del__(self):
90 self.clear()
diff --git a/linden/indra/lib/python/indra/ipc/servicebuilder.py b/linden/indra/lib/python/indra/ipc/servicebuilder.py
index 89cdfad..01f2c6f 100644
--- a/linden/indra/lib/python/indra/ipc/servicebuilder.py
+++ b/linden/indra/lib/python/indra/ipc/servicebuilder.py
@@ -51,12 +51,10 @@ def build(name, context={}, **kwargs):
51 > servicebuilder.build('version-manager-version', context, version='1.18.1.2') 51 > servicebuilder.build('version-manager-version', context, version='1.18.1.2')
52 'http://int.util.vaak.lindenlab.com/channel/Second%20Life%20Release/1.18.1.2' 52 'http://int.util.vaak.lindenlab.com/channel/Second%20Life%20Release/1.18.1.2'
53 """ 53 """
54 context = context.copy() # shouldn't modify the caller's dictionary
55 context.update(kwargs)
56 global _g_builder 54 global _g_builder
57 if _g_builder is None: 55 if _g_builder is None:
58 _g_builder = ServiceBuilder() 56 _g_builder = ServiceBuilder()
59 return _g_builder.buildServiceURL(name, context) 57 return _g_builder.buildServiceURL(name, context, **kwargs)
60 58
61class ServiceBuilder(object): 59class ServiceBuilder(object):
62 def __init__(self, services_definition = services_config): 60 def __init__(self, services_definition = services_config):
@@ -81,13 +79,36 @@ class ServiceBuilder(object):
81 else: 79 else:
82 self.builders[service['name']] = service_builder 80 self.builders[service['name']] = service_builder
83 81
84 def buildServiceURL(self, name, context): 82 def buildServiceURL(self, name, context={}, **kwargs):
85 """\ 83 """\
86 @brief given the environment on construction, return a service URL. 84 @brief given the environment on construction, return a service URL.
87 @param name The name of the service. 85 @param name The name of the service.
88 @param context A dict of name value lookups for the service. 86 @param context A dict of name value lookups for the service.
87 @param kwargs Any keyword arguments are treated as members of the
88 context, this allows you to be all 31337 by writing shit like:
89 servicebuilder.build('name', param=value)
89 @returns Returns the 90 @returns Returns the
90 """ 91 """
92 context = context.copy() # shouldn't modify the caller's dictionary
93 context.update(kwargs)
91 base_url = config.get('services-base-url') 94 base_url = config.get('services-base-url')
92 svc_path = russ.format(self.builders[name], context) 95 svc_path = russ.format(self.builders[name], context)
93 return base_url + svc_path 96 return base_url + svc_path
97
98
99def on_in(query_name, host_key, schema_key):
100 """\
101 @brief Constructs an on/in snippet (for running named queries)
102 from a schema name and two keys referencing values stored in
103 indra.xml.
104
105 @param query_name Name of the query.
106 @param host_key Logical name of destination host. Will be
107 looked up in indra.xml.
108 @param schema_key Logical name of destination schema. Will
109 be looked up in indra.xml.
110 """
111 host_name = config.get(host_key)
112 schema_name = config.get(schema_key)
113 return '/'.join( ('on', host_name, 'in', schema_name, query_name.lstrip('/')) )
114
diff --git a/linden/indra/lib/python/indra/ipc/siesta.py b/linden/indra/lib/python/indra/ipc/siesta.py
index 5fbea29..b206f18 100644
--- a/linden/indra/lib/python/indra/ipc/siesta.py
+++ b/linden/indra/lib/python/indra/ipc/siesta.py
@@ -24,9 +24,9 @@ except ImportError:
24 24
25llsd_parsers = { 25llsd_parsers = {
26 'application/json': json_decode, 26 'application/json': json_decode,
27 'application/llsd+binary': llsd.parse_binary, 27 llsd.BINARY_MIME_TYPE: llsd.parse_binary,
28 'application/llsd+notation': llsd.parse_notation, 28 'application/llsd+notation': llsd.parse_notation,
29 'application/llsd+xml': llsd.parse_xml, 29 llsd.XML_MIME_TYPE: llsd.parse_xml,
30 'application/xml': llsd.parse_xml, 30 'application/xml': llsd.parse_xml,
31 } 31 }
32 32
diff --git a/linden/indra/lib/python/indra/util/llmanifest.py b/linden/indra/lib/python/indra/util/llmanifest.py
index 4675177..a00d242 100644
--- a/linden/indra/lib/python/indra/util/llmanifest.py
+++ b/linden/indra/lib/python/indra/util/llmanifest.py
@@ -584,7 +584,7 @@ class LLManifest(object):
584 584
585 def wildcard_regex(self, src_glob, dst_glob): 585 def wildcard_regex(self, src_glob, dst_glob):
586 src_re = re.escape(src_glob) 586 src_re = re.escape(src_glob)
587 src_re = src_re.replace('\*', '([-a-zA-Z0-9._ ]+)') 587 src_re = src_re.replace('\*', '([-a-zA-Z0-9._ ]*)')
588 dst_temp = dst_glob 588 dst_temp = dst_glob
589 i = 1 589 i = 1
590 while dst_temp.count("*") > 0: 590 while dst_temp.count("*") > 0:
@@ -621,6 +621,7 @@ class LLManifest(object):
621 count = 0 621 count = 0
622 if self.wildcard_pattern.search(src): 622 if self.wildcard_pattern.search(src):
623 for s,d in self.expand_globs(src, dst): 623 for s,d in self.expand_globs(src, dst):
624 assert(s != d)
624 count += self.process_file(s, d) 625 count += self.process_file(s, d)
625 else: 626 else:
626 # if we're specifying a single path (not a glob), 627 # if we're specifying a single path (not a glob),
diff --git a/linden/indra/lib/python/indra/util/llversion.py b/linden/indra/lib/python/indra/util/llversion.py
index 666cce4..fe9448f 100644
--- a/linden/indra/lib/python/indra/util/llversion.py
+++ b/linden/indra/lib/python/indra/util/llversion.py
@@ -50,7 +50,10 @@ def get_version(version_type):
50 m = re.search('const S32 IMP_VERSION_MINOR = (\d+);', file_str) 50 m = re.search('const S32 IMP_VERSION_MINOR = (\d+);', file_str)
51 VER_MINOR = m.group(1) 51 VER_MINOR = m.group(1)
52 m = re.search('const S32 IMP_VERSION_PATCH = (\d+);', file_str) 52 m = re.search('const S32 IMP_VERSION_PATCH = (\d+);', file_str)
53 version = "%(VER_MAJOR)s.%(VER_MINOR)s.%(VER_PATCH)s" % locals() 53 VER_PATCH = m.group(1)
54 m = re.search('const S32 IMP_VERSION_TEST = (\d+);', file_str)
55 VER_BUILD = m.group(1)
56 version = "%(VER_MAJOR)s.%(VER_MINOR)s.%(VER_PATCH)s.%(VER_TEST)s" % locals()
54 return version 57 return version
55 58
56def get_channel(version_type): 59def get_channel(version_type):
diff --git a/linden/indra/lib/python/indra/util/named_query.py b/linden/indra/lib/python/indra/util/named_query.py
index 20f2ec7..788fb0e 100644
--- a/linden/indra/lib/python/indra/util/named_query.py
+++ b/linden/indra/lib/python/indra/util/named_query.py
@@ -47,6 +47,8 @@ except NameError:
47from indra.base import llsd 47from indra.base import llsd
48from indra.base import config 48from indra.base import config
49 49
50DEBUG = False
51
50NQ_FILE_SUFFIX = config.get('named-query-file-suffix', '.nq') 52NQ_FILE_SUFFIX = config.get('named-query-file-suffix', '.nq')
51NQ_FILE_SUFFIX_LEN = len(NQ_FILE_SUFFIX) 53NQ_FILE_SUFFIX_LEN = len(NQ_FILE_SUFFIX)
52 54
@@ -63,7 +65,9 @@ def _init_g_named_manager(sql_dir = None):
63 65
64 # extra fallback directory in case config doesn't return what we want 66 # extra fallback directory in case config doesn't return what we want
65 if sql_dir is None: 67 if sql_dir is None:
66 sql_dir = os.path.dirname(__file__) + "../../../../web/dataservice/sql" 68 sql_dir = os.path.abspath(
69 os.path.join(
70 os.path.realpath(os.path.dirname(__file__)), "..", "..", "..", "..", "web", "dataservice", "sql"))
67 71
68 global _g_named_manager 72 global _g_named_manager
69 _g_named_manager = NamedQueryManager( 73 _g_named_manager = NamedQueryManager(
@@ -103,11 +107,12 @@ class NamedQuery(object):
103 def __init__(self, name, filename): 107 def __init__(self, name, filename):
104 """ Construct a NamedQuery object. The name argument is an 108 """ Construct a NamedQuery object. The name argument is an
105 arbitrary name as a handle for the query, and the filename is 109 arbitrary name as a handle for the query, and the filename is
106 a path to a file containing an llsd named query document.""" 110 a path to a file or a file-like object containing an llsd named
111 query document."""
107 self._stat_interval_seconds = 5 # 5 seconds 112 self._stat_interval_seconds = 5 # 5 seconds
108 self._name = name 113 self._name = name
109 if (filename is not None) \ 114 if (filename is not None and isinstance(filename, (str, unicode))
110 and (NQ_FILE_SUFFIX != filename[-NQ_FILE_SUFFIX_LEN:]): 115 and NQ_FILE_SUFFIX != filename[-NQ_FILE_SUFFIX_LEN:]):
111 filename = filename + NQ_FILE_SUFFIX 116 filename = filename + NQ_FILE_SUFFIX
112 self._location = filename 117 self._location = filename
113 self._alternative = dict() 118 self._alternative = dict()
@@ -122,8 +127,8 @@ class NamedQuery(object):
122 127
123 def get_modtime(self): 128 def get_modtime(self):
124 """ Returns the mtime (last modified time) of the named query 129 """ Returns the mtime (last modified time) of the named query
125 file, if such exists.""" 130 filename. For file-like objects, expect a modtime of 0"""
126 if self._location: 131 if self._location and isinstance(self._location, (str, unicode)):
127 return os.path.getmtime(self._location) 132 return os.path.getmtime(self._location)
128 return 0 133 return 0
129 134
@@ -131,7 +136,12 @@ class NamedQuery(object):
131 """ Loads and parses the named query file into self. Does 136 """ Loads and parses the named query file into self. Does
132 nothing if self.location is nonexistant.""" 137 nothing if self.location is nonexistant."""
133 if self._location: 138 if self._location:
134 self._reference_contents(llsd.parse(open(self._location).read())) 139 if isinstance(self._location, (str, unicode)):
140 contents = llsd.parse(open(self._location).read())
141 else:
142 # we probably have a file-like object. Godspeed!
143 contents = llsd.parse(self._location.read())
144 self._reference_contents(contents)
135 # Check for alternative implementations 145 # Check for alternative implementations
136 try: 146 try:
137 for name, alt in self._contents['alternative'].items(): 147 for name, alt in self._contents['alternative'].items():
@@ -182,6 +192,16 @@ class NamedQuery(object):
182 ready them for use in LIKE statements""" 192 ready them for use in LIKE statements"""
183 if sql: 193 if sql:
184 #print >>sys.stderr, "sql:",sql 194 #print >>sys.stderr, "sql:",sql
195
196 # This first sub is to properly escape any % signs that
197 # are meant to be literally passed through to mysql in the
198 # query. It leaves any %'s that are used for
199 # like-expressions.
200 expr = re.compile("(?<=[^a-zA-Z0-9_-])%(?=[^:])")
201 sql = expr.sub('%%', sql)
202
203 # This should tackle the rest of the %'s in the query, by
204 # converting them to LIKE clauses.
185 expr = re.compile("(%?):([a-zA-Z][a-zA-Z0-9_-]*)%") 205 expr = re.compile("(%?):([a-zA-Z][a-zA-Z0-9_-]*)%")
186 sql = expr.sub(self._prepare_like, sql) 206 sql = expr.sub(self._prepare_like, sql)
187 expr = re.compile("#:([a-zA-Z][a-zA-Z0-9_-]*)") 207 expr = re.compile("#:([a-zA-Z][a-zA-Z0-9_-]*)")
@@ -333,7 +353,8 @@ class NamedQuery(object):
333 cursor = connection.cursor() 353 cursor = connection.cursor()
334 354
335 statement = self.sql(connection, params) 355 statement = self.sql(connection, params)
336 #print "SQL:", statement 356 if DEBUG:
357 print "SQL:", statement
337 rows = cursor.execute(statement) 358 rows = cursor.execute(statement)
338 359
339 # *NOTE: the expect_rows argument is a very cheesy way to get some 360 # *NOTE: the expect_rows argument is a very cheesy way to get some
diff --git a/linden/indra/llcommon/llstat.cpp b/linden/indra/llcommon/llstat.cpp
index 4b79fcb..706acdb 100644
--- a/linden/indra/llcommon/llstat.cpp
+++ b/linden/indra/llcommon/llstat.cpp
@@ -31,55 +31,288 @@
31#include "linden_common.h" 31#include "linden_common.h"
32 32
33#include "llstat.h" 33#include "llstat.h"
34#include "lllivefile.h"
35#include "llerrorcontrol.h"
34#include "llframetimer.h" 36#include "llframetimer.h"
35#include "timing.h" 37#include "timing.h"
38#include "llsd.h"
39#include "llsdserialize.h"
40#include "llstl.h"
41#include "u64.h"
36 42
37class LLStatAccum::impl 43
44// statics
45BOOL LLPerfBlock::sStatsEnabled = FALSE; // Flag for detailed information
46LLPerfBlock::stat_map_t LLPerfBlock::sStatMap; // Map full path string to LLStatTime objects, tracks all active objects
47std::string LLPerfBlock::sCurrentStatPath = ""; // Something like "/total_time/physics/physics step"
48
49//------------------------------------------------------------------------
50// Live config file to trigger stats logging
51static const char STATS_CONFIG_FILE_NAME[] = "/dev/shm/simperf/simperf_proc_config.llsd";
52static const F32 STATS_CONFIG_REFRESH_RATE = 5.0; // seconds
53
54class LLStatsConfigFile : public LLLiveFile
38{ 55{
39public: 56public:
40 static const TimeScale IMPL_NUM_SCALES = (TimeScale)(SCALE_TWO_MINUTE + 1); 57 LLStatsConfigFile()
41 static U64 sScaleTimes[IMPL_NUM_SCALES]; 58 : LLLiveFile(filename(), STATS_CONFIG_REFRESH_RATE),
59 mChanged(false), mStatsp(NULL) { }
42 60
43 BOOL mUseFrameTimer; 61 static std::string filename();
62
63protected:
64 /* virtual */ void loadFile();
44 65
45 BOOL mRunning; 66public:
46 U64 mLastTime; 67 void init(LLPerfStats* statsp);
47 68 static LLStatsConfigFile& instance();
48 struct Bucket 69 // return the singleton stats config file
49 {
50 F64 accum;
51 U64 endTime;
52 70
53 BOOL lastValid; 71 bool mChanged;
54 F64 lastAccum;
55 };
56 72
57 Bucket mBuckets[IMPL_NUM_SCALES]; 73protected:
74 LLPerfStats* mStatsp;
75};
58 76
59 BOOL mLastSampleValid; 77std::string LLStatsConfigFile::filename()
60 F64 mLastSampleValue; 78{
79 return STATS_CONFIG_FILE_NAME;
80}
61 81
82void LLStatsConfigFile::init(LLPerfStats* statsp)
83{
84 mStatsp = statsp;
85}
62 86
63 impl(bool useFrameTimer); 87LLStatsConfigFile& LLStatsConfigFile::instance()
88{
89 static LLStatsConfigFile the_file;
90 return the_file;
91}
64 92
65 void reset(U64 when);
66 93
67 void sum(F64 value); 94/* virtual */
68 void sum(F64 value, U64 when); 95// Load and parse the stats configuration file
96void LLStatsConfigFile::loadFile()
97{
98 if (!mStatsp)
99 {
100 llwarns << "Tries to load performance configure file without initializing LPerfStats" << llendl;
101 return;
102 }
103 mChanged = true;
104
105 LLSD stats_config;
106 {
107 llifstream file(filename().c_str());
108 if (file.is_open())
109 {
110 LLSDSerialize::fromXML(stats_config, file);
111 if (stats_config.isUndefined())
112 {
113 llinfos << "Performance statistics configuration file ill-formed, not recording statistics" << llendl;
114 mStatsp->setReportPerformanceDuration( 0.f );
115 return;
116 }
117 }
118 else
119 { // File went away, turn off stats if it was on
120 if ( mStatsp->frameStatsIsRunning() )
121 {
122 llinfos << "Performance statistics configuration file deleted, not recording statistics" << llendl;
123 mStatsp->setReportPerformanceDuration( 0.f );
124 }
125 return;
126 }
127 }
128
129 F32 duration = 0.f;
130 F32 interval = 0.f;
131
132 const char * w = "duration";
133 if (stats_config.has(w))
134 {
135 duration = (F32)stats_config[w].asReal();
136 }
137 w = "interval";
138 if (stats_config.has(w))
139 {
140 interval = (F32)stats_config[w].asReal();
141 }
142
143 mStatsp->setReportPerformanceDuration( duration );
144 mStatsp->setReportPerformanceInterval( interval );
145
146 if ( duration > 0 )
147 {
148 if ( interval == 0.f )
149 {
150 llinfos << "Recording performance stats every frame for " << duration << " sec" << llendl;
151 }
152 else
153 {
154 llinfos << "Recording performance stats every " << interval << " seconds for " << duration << " seconds" << llendl;
155 }
156 }
157 else
158 {
159 llinfos << "Performance stats recording turned off" << llendl;
160 }
161}
69 162
70 F32 meanValue(TimeScale scale) const;
71 163
72 U64 getCurrentUsecs() const; 164//------------------------------------------------------------------------
73 // Get current microseconds based on timer type
74};
75 165
166LLPerfStats::LLPerfStats(const std::string& process_name, S32 process_pid) :
167 mFrameStatsFileFailure(FALSE),
168 mSkipFirstFrameStats(FALSE),
169 mProcessName(process_name),
170 mProcessPID(process_pid),
171 mReportPerformanceStatInterval(1.f),
172 mReportPerformanceStatEnd(0.0)
173{ }
76 174
77U64 LLStatAccum::impl::sScaleTimes[IMPL_NUM_SCALES] = 175LLPerfStats::~LLPerfStats()
176{
177 LLPerfBlock::clearDynamicStats();
178 mFrameStatsFile.close();
179}
180
181void LLPerfStats::init()
182{
183 // Initialize the stats config file instance.
184 (void) LLStatsConfigFile::instance().init(this);
185 (void) LLStatsConfigFile::instance().checkAndReload();
186}
187
188// Open file for statistics
189void LLPerfStats::openPerfStatsFile()
190{
191 if ( !mFrameStatsFile
192 && !mFrameStatsFileFailure )
193 {
194 std::string stats_file = llformat("/dev/shm/simperf/%s_proc.%d.llsd", mProcessName.c_str(), mProcessPID);
195 mFrameStatsFile.close();
196 mFrameStatsFile.clear();
197 mFrameStatsFile.open(stats_file, llofstream::out);
198 if ( mFrameStatsFile.fail() )
199 {
200 llinfos << "Error opening statistics log file " << stats_file << llendl;
201 mFrameStatsFileFailure = TRUE;
202 }
203 else
204 {
205 LLSD process_info = LLSD::emptyMap();
206 process_info["name"] = mProcessName;
207 process_info["pid"] = (LLSD::Integer) mProcessPID;
208 process_info["stat_rate"] = (LLSD::Integer) mReportPerformanceStatInterval;
209 // Add process-specific info.
210 addProcessHeaderInfo(process_info);
211
212 mFrameStatsFile << LLSDNotationStreamer(process_info) << std::endl;
213 }
214 }
215}
216
217// Dump out performance metrics over some time interval
218void LLPerfStats::dumpIntervalPerformanceStats()
219{
220 // Ensure output file is OK
221 openPerfStatsFile();
222
223 if ( mFrameStatsFile )
224 {
225 LLSD stats = LLSD::emptyMap();
226
227 LLStatAccum::TimeScale scale;
228 if ( getReportPerformanceInterval() == 0.f )
229 {
230 scale = LLStatAccum::SCALE_PER_FRAME;
231 }
232 else if ( getReportPerformanceInterval() < 0.5f )
233 {
234 scale = LLStatAccum::SCALE_100MS;
235 }
236 else
237 {
238 scale = LLStatAccum::SCALE_SECOND;
239 }
240
241 // Write LLSD into log
242 stats["utc_time"] = (LLSD::String) LLError::utcTime();
243 stats["timestamp"] = U64_to_str((totalTime() / 1000) + (gUTCOffset * 1000)); // milliseconds since epoch
244 stats["frame_number"] = (LLSD::Integer) LLFrameTimer::getFrameCount();
245
246 // Add process-specific frame info.
247 addProcessFrameInfo(stats, scale);
248 LLPerfBlock::addStatsToLLSDandReset( stats, scale );
249
250 mFrameStatsFile << LLSDNotationStreamer(stats) << std::endl;
251 }
252}
253
254// Set length of performance stat recording
255void LLPerfStats::setReportPerformanceDuration( F32 seconds )
256{
257 if ( seconds <= 0.f )
258 {
259 mReportPerformanceStatEnd = 0.0;
260 LLPerfBlock::setStatsEnabled( FALSE );
261 mFrameStatsFile.close();
262 LLPerfBlock::clearDynamicStats();
263 }
264 else
265 {
266 mReportPerformanceStatEnd = LLFrameTimer::getElapsedSeconds() + ((F64) seconds);
267 // Clear failure flag to try and create the log file once
268 mFrameStatsFileFailure = FALSE;
269 LLPerfBlock::setStatsEnabled( TRUE );
270 mSkipFirstFrameStats = TRUE; // Skip the first report (at the end of this frame)
271 }
272}
273
274void LLPerfStats::updatePerFrameStats()
275{
276 (void) LLStatsConfigFile::instance().checkAndReload();
277 static LLFrameTimer performance_stats_timer;
278 if ( frameStatsIsRunning() )
279 {
280 if ( mReportPerformanceStatInterval == 0 )
281 { // Record info every frame
282 if ( mSkipFirstFrameStats )
283 { // Skip the first time - was started this frame
284 mSkipFirstFrameStats = FALSE;
285 }
286 else
287 {
288 dumpIntervalPerformanceStats();
289 }
290 }
291 else
292 {
293 performance_stats_timer.setTimerExpirySec( getReportPerformanceInterval() );
294 if (performance_stats_timer.checkExpirationAndReset( mReportPerformanceStatInterval ))
295 {
296 dumpIntervalPerformanceStats();
297 }
298 }
299
300 if ( LLFrameTimer::getElapsedSeconds() > mReportPerformanceStatEnd )
301 { // Reached end of time, clear it to stop reporting
302 setReportPerformanceDuration(0.f); // Don't set mReportPerformanceStatEnd directly
303 llinfos << "Recording performance stats completed" << llendl;
304 }
305 }
306}
307
308
309//------------------------------------------------------------------------
310
311U64 LLStatAccum::sScaleTimes[NUM_SCALES] =
78{ 312{
79 USEC_PER_SEC / 10, // 100 millisec 313 USEC_PER_SEC / 10, // 100 millisec
80 USEC_PER_SEC * 1, // seconds 314 USEC_PER_SEC * 1, // seconds
81 USEC_PER_SEC * 60, // minutes 315 USEC_PER_SEC * 60, // minutes
82 USEC_PER_SEC * 60 * 2 // two minutes
83#if ENABLE_LONG_TIME_STATS 316#if ENABLE_LONG_TIME_STATS
84 // enable these when more time scales are desired 317 // enable these when more time scales are desired
85 USEC_PER_SEC * 60*60, // hours 318 USEC_PER_SEC * 60*60, // hours
@@ -89,19 +322,27 @@ U64 LLStatAccum::impl::sScaleTimes[IMPL_NUM_SCALES] =
89}; 322};
90 323
91 324
92LLStatAccum::impl::impl(bool useFrameTimer) 325
326LLStatAccum::LLStatAccum(bool useFrameTimer)
327 : mUseFrameTimer(useFrameTimer),
328 mRunning(FALSE),
329 mLastSampleValue(0.0),
330 mLastSampleValid(FALSE)
331{
332}
333
334LLStatAccum::~LLStatAccum()
93{ 335{
94 mUseFrameTimer = useFrameTimer;
95 mRunning = FALSE;
96 mLastSampleValid = FALSE;
97} 336}
98 337
99void LLStatAccum::impl::reset(U64 when) 338
339
340void LLStatAccum::reset(U64 when)
100{ 341{
101 mRunning = TRUE; 342 mRunning = TRUE;
102 mLastTime = when; 343 mLastTime = when;
103 344
104 for (int i = 0; i < IMPL_NUM_SCALES; ++i) 345 for (int i = 0; i < NUM_SCALES; ++i)
105 { 346 {
106 mBuckets[i].accum = 0.0; 347 mBuckets[i].accum = 0.0;
107 mBuckets[i].endTime = when + sScaleTimes[i]; 348 mBuckets[i].endTime = when + sScaleTimes[i];
@@ -109,12 +350,12 @@ void LLStatAccum::impl::reset(U64 when)
109 } 350 }
110} 351}
111 352
112void LLStatAccum::impl::sum(F64 value) 353void LLStatAccum::sum(F64 value)
113{ 354{
114 sum(value, getCurrentUsecs()); 355 sum(value, getCurrentUsecs());
115} 356}
116 357
117void LLStatAccum::impl::sum(F64 value, U64 when) 358void LLStatAccum::sum(F64 value, U64 when)
118{ 359{
119 if (!mRunning) 360 if (!mRunning)
120 { 361 {
@@ -131,7 +372,10 @@ void LLStatAccum::impl::sum(F64 value, U64 when)
131 return; 372 return;
132 } 373 }
133 374
134 for (int i = 0; i < IMPL_NUM_SCALES; ++i) 375 // how long is this value for
376 U64 timeSpan = when - mLastTime;
377
378 for (int i = 0; i < NUM_SCALES; ++i)
135 { 379 {
136 Bucket& bucket = mBuckets[i]; 380 Bucket& bucket = mBuckets[i];
137 381
@@ -143,8 +387,6 @@ void LLStatAccum::impl::sum(F64 value, U64 when)
143 { 387 {
144 U64 timeScale = sScaleTimes[i]; 388 U64 timeScale = sScaleTimes[i];
145 389
146 U64 timeSpan = when - mLastTime;
147 // how long is this value for
148 U64 timeLeft = when - bucket.endTime; 390 U64 timeLeft = when - bucket.endTime;
149 // how much time is left after filling this bucket 391 // how much time is left after filling this bucket
150 392
@@ -173,13 +415,18 @@ void LLStatAccum::impl::sum(F64 value, U64 when)
173} 415}
174 416
175 417
176F32 LLStatAccum::impl::meanValue(TimeScale scale) const 418F32 LLStatAccum::meanValue(TimeScale scale) const
177{ 419{
178 if (!mRunning) 420 if (!mRunning)
179 { 421 {
180 return 0.0; 422 return 0.0;
181 } 423 }
182 if (scale < 0 || scale >= IMPL_NUM_SCALES) 424 if ( scale == SCALE_PER_FRAME )
425 { // Per-frame not supported here
426 scale = SCALE_100MS;
427 }
428
429 if (scale < 0 || scale >= NUM_SCALES)
183 { 430 {
184 llwarns << "llStatAccum::meanValue called for unsupported scale: " 431 llwarns << "llStatAccum::meanValue called for unsupported scale: "
185 << scale << llendl; 432 << scale << llendl;
@@ -209,7 +456,7 @@ F32 LLStatAccum::impl::meanValue(TimeScale scale) const
209} 456}
210 457
211 458
212U64 LLStatAccum::impl::getCurrentUsecs() const 459U64 LLStatAccum::getCurrentUsecs() const
213{ 460{
214 if (mUseFrameTimer) 461 if (mUseFrameTimer)
215 { 462 {
@@ -222,25 +469,44 @@ U64 LLStatAccum::impl::getCurrentUsecs() const
222} 469}
223 470
224 471
472// ------------------------------------------------------------------------
225 473
226 474LLStatRate::LLStatRate(bool use_frame_timer)
227 475 : LLStatAccum(use_frame_timer)
228LLStatAccum::LLStatAccum(bool useFrameTimer)
229 : m(* new impl(useFrameTimer))
230{ 476{
231} 477}
232 478
233LLStatAccum::~LLStatAccum() 479void LLStatRate::count(U32 value)
234{ 480{
235 delete &m; 481 sum((F64)value * sScaleTimes[SCALE_SECOND]);
236} 482}
237 483
238F32 LLStatAccum::meanValue(TimeScale scale) const 484
239{ 485void LLStatRate::mark()
240 return m.meanValue(scale); 486 {
241} 487 // Effectively the same as count(1), but sets mLastSampleValue
488 U64 when = getCurrentUsecs();
489
490 if ( mRunning
491 && (when > mLastTime) )
492 { // Set mLastSampleValue to the time from the last mark()
493 F64 duration = ((F64)(when - mLastTime)) / sScaleTimes[SCALE_SECOND];
494 if ( duration > 0.0 )
495 {
496 mLastSampleValue = 1.0 / duration;
497 }
498 else
499 {
500 mLastSampleValue = 0.0;
501 }
502 }
503
504 sum( (F64) sScaleTimes[SCALE_SECOND], when);
505 }
242 506
243 507
508// ------------------------------------------------------------------------
509
244 510
245LLStatMeasure::LLStatMeasure(bool use_frame_timer) 511LLStatMeasure::LLStatMeasure(bool use_frame_timer)
246 : LLStatAccum(use_frame_timer) 512 : LLStatAccum(use_frame_timer)
@@ -249,53 +515,209 @@ LLStatMeasure::LLStatMeasure(bool use_frame_timer)
249 515
250void LLStatMeasure::sample(F64 value) 516void LLStatMeasure::sample(F64 value)
251{ 517{
252 U64 when = m.getCurrentUsecs(); 518 U64 when = getCurrentUsecs();
253 519
254 if (m.mLastSampleValid) 520 if (mLastSampleValid)
255 { 521 {
256 F64 avgValue = (value + m.mLastSampleValue) / 2.0; 522 F64 avgValue = (value + mLastSampleValue) / 2.0;
257 F64 interval = (F64)(when - m.mLastTime); 523 F64 interval = (F64)(when - mLastTime);
258 524
259 m.sum(avgValue * interval, when); 525 sum(avgValue * interval, when);
260 } 526 }
261 else 527 else
262 { 528 {
263 m.reset(when); 529 reset(when);
264 } 530 }
265 531
266 m.mLastSampleValid = TRUE; 532 mLastSampleValid = TRUE;
267 m.mLastSampleValue = value; 533 mLastSampleValue = value;
268} 534}
269 535
270 536
271LLStatRate::LLStatRate(bool use_frame_timer) 537// ------------------------------------------------------------------------
272 : LLStatAccum(use_frame_timer) 538
539LLStatTime::LLStatTime(const std::string & key)
540 : LLStatAccum(false),
541 mFrameNumber(LLFrameTimer::getFrameCount()),
542 mTotalTimeInFrame(0),
543 mKey(key)
544#if LL_DEBUG
545 , mRunning(FALSE)
546#endif
273{ 547{
274} 548}
275 549
276void LLStatRate::count(U32 value) 550void LLStatTime::start()
551{
552 // Reset frame accumluation if the frame number has changed
553 U32 frame_number = LLFrameTimer::getFrameCount();
554 if ( frame_number != mFrameNumber )
555 {
556 mFrameNumber = frame_number;
557 mTotalTimeInFrame = 0;
558 }
559
560 sum(0.0);
561
562#if LL_DEBUG
563 // Shouldn't be running already
564 llassert( !mRunning );
565 mRunning = TRUE;
566#endif
567}
568
569void LLStatTime::stop()
570{
571 U64 end_time = getCurrentUsecs();
572 U64 duration = end_time - mLastTime;
573 sum(F64(duration), end_time);
574 //llinfos << "mTotalTimeInFrame incremented from " << mTotalTimeInFrame << " to " << (mTotalTimeInFrame + duration) << llendl;
575 mTotalTimeInFrame += duration;
576
577#if LL_DEBUG
578 mRunning = FALSE;
579#endif
580}
581
582/* virtual */ F32 LLStatTime::meanValue(TimeScale scale) const
277{ 583{
278 m.sum((F64)value * impl::sScaleTimes[SCALE_SECOND]); 584 if ( LLStatAccum::SCALE_PER_FRAME == scale )
585 {
586 return mTotalTimeInFrame;
587 }
588 else
589 {
590 return LLStatAccum::meanValue(scale);
591 }
279} 592}
280 593
281 594
282LLStatTime::LLStatTime(bool use_frame_timer) 595// ------------------------------------------------------------------------
283 : LLStatAccum(use_frame_timer) 596
597
598// Use this constructor for pre-defined LLStatTime objects
599LLPerfBlock::LLPerfBlock(LLStatTime* stat ) : mPredefinedStat(stat), mDynamicStat(NULL)
284{ 600{
601 if (mPredefinedStat)
602 {
603 // If dynamic stats are turned on, this will create a separate entry in the stat map.
604 initDynamicStat(mPredefinedStat->mKey);
605
606 // Start predefined stats. These stats are not part of the stat map.
607 mPredefinedStat->start();
608 }
285} 609}
286 610
287void LLStatTime::start() 611// Use this constructor for dynamically created LLStatTime objects (not pre-defined) with a multi-part key.
612// These are also turned on or off via the switch passed in
613LLPerfBlock::LLPerfBlock( const char* key1, const char* key2 ) : mPredefinedStat(NULL), mDynamicStat(NULL)
288{ 614{
289 m.sum(0.0); 615 if (!sStatsEnabled) return;
616
617 if (NULL == key2 || strlen(key2) == 0)
618 {
619 initDynamicStat(key1);
620 }
621 else
622 {
623 std::ostringstream key;
624 key << key1 << "_" << key2;
625 initDynamicStat(key.str());
626 }
290} 627}
291 628
292void LLStatTime::stop() 629void LLPerfBlock::initDynamicStat(const std::string& key)
630{
631 // Early exit if dynamic stats aren't enabled.
632 if (!sStatsEnabled) return;
633
634 mLastPath = sCurrentStatPath; // Save and restore current path
635 sCurrentStatPath += "/" + key; // Add key to current path
636
637 // See if the LLStatTime object already exists
638 stat_map_t::iterator iter = sStatMap.find(sCurrentStatPath);
639 if ( iter == sStatMap.end() )
640 {
641 // StatEntry object doesn't exist, so create it
642 mDynamicStat = new StatEntry( key );
643 sStatMap[ sCurrentStatPath ] = mDynamicStat; // Set the entry for this path
644 }
645 else
646 {
647 // Found this path in the map, use the object there
648 mDynamicStat = (*iter).second; // Get StatEntry for the current path
649 }
650
651 if (mDynamicStat)
652 {
653 mDynamicStat->mStat.start();
654 mDynamicStat->mCount++;
655 }
656 else
657 {
658 llwarns << "Initialized NULL dynamic stat at '" << sCurrentStatPath << "'" << llendl;
659 sCurrentStatPath = mLastPath;
660 }
661}
662
663
664// Destructor does the time accounting
665LLPerfBlock::~LLPerfBlock()
666{
667 if (mPredefinedStat) mPredefinedStat->stop();
668 if (mDynamicStat)
669 {
670 mDynamicStat->mStat.stop();
671 sCurrentStatPath = mLastPath; // Restore the path in case sStatsEnabled changed during this block
672 }
673}
674
675
676// Clear the map of any dynamic stats. Static routine
677void LLPerfBlock::clearDynamicStats()
678{
679 std::for_each(sStatMap.begin(), sStatMap.end(), DeletePairedPointer());
680 sStatMap.clear();
681}
682
683// static - Extract the stat info into LLSD
684void LLPerfBlock::addStatsToLLSDandReset( LLSD & stats,
685 LLStatAccum::TimeScale scale )
293{ 686{
294 U64 endTime = m.getCurrentUsecs(); 687 // If we aren't in per-frame scale, we need to go from second to microsecond.
295 m.sum((F64)(endTime - m.mLastTime), endTime); 688 U32 scale_adjustment = 1;
689 if (LLStatAccum::SCALE_PER_FRAME != scale)
690 {
691 scale_adjustment = USEC_PER_SEC;
692 }
693 stat_map_t::iterator iter = sStatMap.begin();
694 for ( ; iter != sStatMap.end(); ++iter )
695 { // Put the entry into LLSD "/full/path/to/stat/" = microsecond total time
696 const std::string & stats_full_path = (*iter).first;
697
698 StatEntry * stat = (*iter).second;
699 if (stat)
700 {
701 if (stat->mCount > 0)
702 {
703 stats[stats_full_path] = LLSD::emptyMap();
704 stats[stats_full_path]["us"] = (LLSD::Integer) (scale_adjustment * stat->mStat.meanValue(scale));
705 if (stat->mCount > 1)
706 {
707 stats[stats_full_path]["count"] = (LLSD::Integer) stat->mCount;
708 }
709 stat->mCount = 0;
710 }
711 }
712 else
713 { // WTF? Shouldn't have a NULL pointer in the map.
714 llwarns << "Unexpected NULL dynamic stat at '" << stats_full_path << "'" << llendl;
715 }
716 }
296} 717}
297 718
298 719
720// ------------------------------------------------------------------------
299 721
300LLTimer LLStat::sTimer; 722LLTimer LLStat::sTimer;
301LLFrameTimer LLStat::sFrameTimer; 723LLFrameTimer LLStat::sFrameTimer;
diff --git a/linden/indra/llcommon/llstat.h b/linden/indra/llcommon/llstat.h
index 0a7e014..63813e2 100644
--- a/linden/indra/llcommon/llstat.h
+++ b/linden/indra/llcommon/llstat.h
@@ -33,9 +33,13 @@
33#define LL_LLSTAT_H 33#define LL_LLSTAT_H
34 34
35#include <deque> 35#include <deque>
36#include <map>
36 37
37#include "lltimer.h" 38#include "lltimer.h"
38#include "llframetimer.h" 39#include "llframetimer.h"
40#include "llfile.h"
41
42class LLSD;
39 43
40// Set this if longer stats are needed 44// Set this if longer stats are needed
41#define ENABLE_LONG_TIME_STATS 0 45#define ENABLE_LONG_TIME_STATS 0
@@ -58,25 +62,50 @@ public:
58 SCALE_100MS, 62 SCALE_100MS,
59 SCALE_SECOND, 63 SCALE_SECOND,
60 SCALE_MINUTE, 64 SCALE_MINUTE,
61 SCALE_TWO_MINUTE,
62#if ENABLE_LONG_TIME_STATS 65#if ENABLE_LONG_TIME_STATS
63 SCALE_HOUR, 66 SCALE_HOUR,
64 SCALE_DAY, 67 SCALE_DAY,
65 SCALE_WEEK, 68 SCALE_WEEK,
66#endif 69#endif
67 NUM_SCALES 70 NUM_SCALES, // Use to size storage arrays
71 SCALE_PER_FRAME // For latest frame information - should be after NUM_SCALES since this doesn't go into the time buckets
68 }; 72 };
69 73
70 F32 meanValue(TimeScale scale) const; 74 static U64 sScaleTimes[NUM_SCALES];
75
76 virtual F32 meanValue(TimeScale scale) const;
71 // see the subclasses for the specific meaning of value 77 // see the subclasses for the specific meaning of value
72 78
73 F32 meanValueOverLast100ms() const { return meanValue(SCALE_100MS); } 79 F32 meanValueOverLast100ms() const { return meanValue(SCALE_100MS); }
74 F32 meanValueOverLastSecond() const { return meanValue(SCALE_SECOND); } 80 F32 meanValueOverLastSecond() const { return meanValue(SCALE_SECOND); }
75 F32 meanValueOverLastMinute() const { return meanValue(SCALE_MINUTE); } 81 F32 meanValueOverLastMinute() const { return meanValue(SCALE_MINUTE); }
76 82
77protected: 83 void reset(U64 when);
78 class impl; 84
79 impl& m; 85 void sum(F64 value);
86 void sum(F64 value, U64 when);
87
88 U64 getCurrentUsecs() const;
89 // Get current microseconds based on timer type
90
91 BOOL mUseFrameTimer;
92 BOOL mRunning;
93
94 U64 mLastTime;
95
96 struct Bucket
97 {
98 F64 accum;
99 U64 endTime;
100
101 BOOL lastValid;
102 F64 lastAccum;
103 };
104
105 Bucket mBuckets[NUM_SCALES];
106
107 BOOL mLastSampleValid;
108 F64 mLastSampleValue;
80}; 109};
81 110
82class LLStatMeasure : public LLStatAccum 111class LLStatMeasure : public LLStatAccum
@@ -105,39 +134,120 @@ public:
105 void count(U32); 134 void count(U32);
106 // used to note that n items have occured 135 // used to note that n items have occured
107 136
108 void mark() { count(1); } 137 void mark();
109 // used for counting the rate thorugh a point in the code 138 // used for counting the rate thorugh a point in the code
110}; 139};
111 140
112 141
113class LLTimeBlock;
114
115class LLStatTime : public LLStatAccum 142class LLStatTime : public LLStatAccum
116 // gathers statistics about time spent in a block of code 143 // gathers statistics about time spent in a block of code
117 // measure average duration per second in the block 144 // measure average duration per second in the block
118{ 145{
119public: 146public:
120 LLStatTime(bool use_frame_timer = false); 147 LLStatTime( const std::string & key = "undefined" );
148
149 U32 mFrameNumber; // Current frame number
150 U64 mTotalTimeInFrame; // Total time (microseconds) accumulated during the last frame
151
152 void setKey( const std::string & key ) { mKey = key; };
153
154 virtual F32 meanValue(TimeScale scale) const;
121 155
122private: 156private:
123 void start(); 157 void start(); // Start and stop measuring time block
124 void stop(); 158 void stop();
125 friend class LLTimeBlock; 159
160 std::string mKey; // Tag representing this time block
161
162#if LL_DEBUG
163 BOOL mRunning; // TRUE if start() has been called
164#endif
165
166 friend class LLPerfBlock;
126}; 167};
127 168
128class LLTimeBlock 169// ----------------------------------------------------------------------------
170
171
172// Use this class on the stack to record statistics about an area of code
173class LLPerfBlock
129{ 174{
130public: 175public:
131 LLTimeBlock(LLStatTime& stat) : mStat(stat) { mStat.start(); } 176 struct StatEntry
132 ~LLTimeBlock() { mStat.stop(); } 177 {
178 StatEntry(const std::string& key) : mStat(LLStatTime(key)), mCount(0) {}
179 LLStatTime mStat;
180 U32 mCount;
181 };
182 typedef std::map<std::string, StatEntry*> stat_map_t;
183
184 // Use this constructor for pre-defined LLStatTime objects
185 LLPerfBlock(LLStatTime* stat);
186
187 // Use this constructor for dynamically created LLStatTime objects (not pre-defined) with a multi-part key
188 LLPerfBlock( const char* key1, const char* key2 = NULL);
189
190
191 ~LLPerfBlock();
192
193 static void setStatsEnabled( BOOL enable ) { sStatsEnabled = enable; };
194 static S32 getStatsEnabled() { return sStatsEnabled; };
195
196 static void clearDynamicStats(); // Reset maps to clear out dynamic objects
197 static void addStatsToLLSDandReset( LLSD & stats, // Get current information and clear time bin
198 LLStatAccum::TimeScale scale );
199
133private: 200private:
134 LLStatTime& mStat; 201 // Initialize dynamically created LLStatTime objects
202 void initDynamicStat(const std::string& key);
203
204 std::string mLastPath; // Save sCurrentStatPath when this is called
205 LLStatTime * mPredefinedStat; // LLStatTime object to get data
206 StatEntry * mDynamicStat; // StatEntryobject to get data
207
208 static BOOL sStatsEnabled; // Normally FALSE
209 static stat_map_t sStatMap; // Map full path string to LLStatTime objects
210 static std::string sCurrentStatPath; // Something like "frame/physics/physics step"
135}; 211};
136 212
213// ----------------------------------------------------------------------------
137 214
215class LLPerfStats
216{
217public:
218 LLPerfStats(const std::string& process_name = "unknown", S32 process_pid = 0);
219 virtual ~LLPerfStats();
220
221 virtual void init(); // Reset and start all stat timers
222 virtual void updatePerFrameStats();
223 // Override these function to add process-specific information to the performance log header and per-frame logging.
224 virtual void addProcessHeaderInfo(LLSD& info) { /* not implemented */ }
225 virtual void addProcessFrameInfo(LLSD& info, LLStatAccum::TimeScale scale) { /* not implemented */ }
226
227 // High-resolution frame stats
228 BOOL frameStatsIsRunning() { return (mReportPerformanceStatEnd > 0.); };
229 F32 getReportPerformanceInterval() const { return mReportPerformanceStatInterval; };
230 void setReportPerformanceInterval( F32 interval ) { mReportPerformanceStatInterval = interval; };
231 void setReportPerformanceDuration( F32 seconds );
232 void setProcessName(const std::string& process_name) { mProcessName = process_name; }
233 void setProcessPID(S32 process_pid) { mProcessPID = process_pid; }
138 234
235protected:
236 void openPerfStatsFile(); // Open file for high resolution metrics logging
237 void dumpIntervalPerformanceStats();
238
239 llofstream mFrameStatsFile; // File for per-frame stats
240 BOOL mFrameStatsFileFailure; // Flag to prevent repeat opening attempts
241 BOOL mSkipFirstFrameStats; // Flag to skip one (partial) frame report
242 std::string mProcessName;
243 S32 mProcessPID;
139 244
245private:
246 F32 mReportPerformanceStatInterval; // Seconds between performance stats
247 F64 mReportPerformanceStatEnd; // End time (seconds) for performance stats
248};
140 249
250// ----------------------------------------------------------------------------
141class LLStat 251class LLStat
142{ 252{
143public: 253public:
diff --git a/linden/indra/llmath/llmodularmath.h b/linden/indra/llmath/llmodularmath.h
new file mode 100644
index 0000000..67083ea
--- /dev/null
+++ b/linden/indra/llmath/llmodularmath.h
@@ -0,0 +1,57 @@
1/**
2 * @file llmodularmath.h
3 * @brief Useful modular math functions.
4 *
5 * $LicenseInfo:firstyear=2008&license=viewergpl$
6 *
7 * Copyright (c) 2008-2009, Linden Research, Inc.
8 *
9 * Second Life Viewer Source Code
10 * The source code in this file ("Source Code") is provided by Linden Lab
11 * to you under the terms of the GNU General Public License, version 2.0
12 * ("GPL"), unless you have obtained a separate licensing agreement
13 * ("Other License"), formally executed by you and Linden Lab. Terms of
14 * the GPL can be found in doc/GPL-license.txt in this distribution, or
15 * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
16 *
17 * There are special exceptions to the terms and conditions of the GPL as
18 * it is applied to this Source Code. View the full text of the exception
19 * in the file doc/FLOSS-exception.txt in this software distribution, or
20 * online at http://secondlifegrid.net/programs/open_source/licensing/flossexception
21 *
22 * By copying, modifying or distributing this software, you acknowledge
23 * that you have read and understood your obligations described above,
24 * and agree to abide by those obligations.
25 *
26 * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
27 * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
28 * COMPLETENESS OR PERFORMANCE.
29 * $/LicenseInfo$
30 */
31
32#ifndef LLMODULARMATH_H
33#define LLMODULARMATH_H
34
35namespace LLModularMath
36{
37 // Return difference between lhs and rhs
38 // treating the U32 operands and result
39 // as unsigned values of given width.
40 template<int width>
41 inline U32 subtract(U32 lhs, U32 rhs)
42 {
43 // Generate a bit mask which will truncate
44 // unsigned values to given width at compile time.
45 const U32 mask = (1 << width) - 1;
46
47 // Operands are unsigned, so modular
48 // arithmetic applies. If lhs < rhs,
49 // difference will wrap in to lower
50 // bits of result, which is then masked
51 // to give a value that can be represented
52 // by an unsigned value of width bits.
53 return mask & (lhs - rhs);
54 }
55}
56
57#endif
diff --git a/linden/indra/llmessage/llcircuit.cpp b/linden/indra/llmessage/llcircuit.cpp
index 12a1520..7b2f241 100644
--- a/linden/indra/llmessage/llcircuit.cpp
+++ b/linden/indra/llmessage/llcircuit.cpp
@@ -60,6 +60,7 @@
60#include "llrand.h" 60#include "llrand.h"
61#include "llstl.h" 61#include "llstl.h"
62#include "lltransfermanager.h" 62#include "lltransfermanager.h"
63#include "llmodularmath.h"
63 64
64const F32 PING_INTERVAL = 5.f; // seconds 65const F32 PING_INTERVAL = 5.f; // seconds
65const S32 PING_START_BLOCK = 3; // How many pings behind we have to be to consider ourself blocked. 66const S32 PING_START_BLOCK = 3; // How many pings behind we have to be to consider ourself blocked.
@@ -676,6 +677,8 @@ void LLCircuitData::checkPacketInID(TPACKETID id, BOOL receive_resent)
676 mPacketsIn++; 677 mPacketsIn++;
677 setPacketInID((id + 1) % LL_MAX_OUT_PACKET_ID); 678 setPacketInID((id + 1) % LL_MAX_OUT_PACKET_ID);
678 679
680 mLastPacketGap = 0;
681 mOutOfOrderRate.count(0);
679 return; 682 return;
680 } 683 }
681 684
@@ -683,6 +686,7 @@ void LLCircuitData::checkPacketInID(TPACKETID id, BOOL receive_resent)
683 686
684 687
685 // now, check to see if we've got a gap 688 // now, check to see if we've got a gap
689 U32 gap = 0;
686 if ((mPacketsInID == id)) 690 if ((mPacketsInID == id))
687 { 691 {
688 // nope! bump and wrap the counter, then return 692 // nope! bump and wrap the counter, then return
@@ -704,6 +708,11 @@ void LLCircuitData::checkPacketInID(TPACKETID id, BOOL receive_resent)
704 // otherwise, walk from mCurrentCircuit->mPacketsInID to id with wrapping, adding the values to the map 708 // otherwise, walk from mCurrentCircuit->mPacketsInID to id with wrapping, adding the values to the map
705 // and setting mPacketsInID to id + 1 % LL_MAX_OUT_PACKET_ID 709 // and setting mPacketsInID to id + 1 % LL_MAX_OUT_PACKET_ID
706 710
711 // babbage: all operands in expression are unsigned, so modular
712 // arithmetic will always find correct gap, regardless of wrap arounds.
713 const U8 width = 24;
714 gap = LLModularMath::subtract<width>(mPacketsInID, id);
715
707 if (mPotentialLostPackets.find(id) != mPotentialLostPackets.end()) 716 if (mPotentialLostPackets.find(id) != mPotentialLostPackets.end())
708 { 717 {
709 if(gMessageSystem->mVerboseLog) 718 if(gMessageSystem->mVerboseLog)
@@ -765,6 +774,8 @@ void LLCircuitData::checkPacketInID(TPACKETID id, BOOL receive_resent)
765 774
766 } 775 }
767 } 776 }
777 mOutOfOrderRate.count(gap);
778 mLastPacketGap = gap;
768} 779}
769 780
770 781
diff --git a/linden/indra/llmessage/llcircuit.h b/linden/indra/llmessage/llcircuit.h
index 552b50f..b53c955 100644
--- a/linden/indra/llmessage/llcircuit.h
+++ b/linden/indra/llmessage/llcircuit.h
@@ -45,6 +45,7 @@
45#include "llpacketack.h" 45#include "llpacketack.h"
46#include "lluuid.h" 46#include "lluuid.h"
47#include "llthrottle.h" 47#include "llthrottle.h"
48#include "llstat.h"
48 49
49// 50//
50// Constants 51// Constants
@@ -133,6 +134,10 @@ public:
133 S32 getUnackedPacketCount() const { return mUnackedPacketCount; } 134 S32 getUnackedPacketCount() const { return mUnackedPacketCount; }
134 S32 getUnackedPacketBytes() const { return mUnackedPacketBytes; } 135 S32 getUnackedPacketBytes() const { return mUnackedPacketBytes; }
135 F64 getNextPingSendTime() const { return mNextPingSendTime; } 136 F64 getNextPingSendTime() const { return mNextPingSendTime; }
137 F32 getOutOfOrderRate(LLStatAccum::TimeScale scale = LLStatAccum::SCALE_MINUTE)
138 { return mOutOfOrderRate.meanValue(scale); }
139 U32 getLastPacketGap() const { return mLastPacketGap; }
140 LLHost getHost() const { return mHost; }
136 141
137 LLThrottleGroup &getThrottleGroup() { return mThrottles; } 142 LLThrottleGroup &getThrottleGroup() { return mThrottles; }
138 143
@@ -276,6 +281,9 @@ protected:
276 LLTimer mExistenceTimer; // initialized when circuit created, used to track bandwidth numbers 281 LLTimer mExistenceTimer; // initialized when circuit created, used to track bandwidth numbers
277 282
278 S32 mCurrentResendCount; // Number of resent packets since last spam 283 S32 mCurrentResendCount; // Number of resent packets since last spam
284 LLStatRate mOutOfOrderRate; // Rate of out of order packets coming in.
285 U32 mLastPacketGap; // Gap in sequence number of last packet.
286
279}; 287};
280 288
281 289
diff --git a/linden/indra/llmessage/llcurl.cpp b/linden/indra/llmessage/llcurl.cpp
index 834ec4b..167e237 100644
--- a/linden/indra/llmessage/llcurl.cpp
+++ b/linden/indra/llmessage/llcurl.cpp
@@ -265,6 +265,10 @@ LLCurl::Easy* LLCurl::Easy::getEasy()
265 delete easy; 265 delete easy;
266 return NULL; 266 return NULL;
267 } 267 }
268
269 // set no DMS caching as default for all easy handles. This prevents them adopting a
270 // multi handles cache if they are added to one.
271 curl_easy_setopt(easy->mCurlEasyHandle, CURLOPT_DNS_CACHE_TIMEOUT, 0);
268 ++gCurlEasyCount; 272 ++gCurlEasyCount;
269 return easy; 273 return easy;
270} 274}
@@ -747,7 +751,7 @@ bool LLCurlRequest::post(const std::string& url, const LLSD& data, LLCurl::Respo
747 easy->setopt(CURLOPT_POSTFIELDS, (void*)NULL); 751 easy->setopt(CURLOPT_POSTFIELDS, (void*)NULL);
748 easy->setopt(CURLOPT_POSTFIELDSIZE, bytes); 752 easy->setopt(CURLOPT_POSTFIELDSIZE, bytes);
749 753
750 easy->slist_append("Content-Type: application/xml"); 754 easy->slist_append("Content-Type: application/llsd+xml");
751 easy->setHeaders(); 755 easy->setHeaders();
752 756
753 lldebugs << "POSTING: " << bytes << " bytes." << llendl; 757 lldebugs << "POSTING: " << bytes << " bytes." << llendl;
diff --git a/linden/indra/llmessage/llhttpassetstorage.cpp b/linden/indra/llmessage/llhttpassetstorage.cpp
index fdd521f..6d5a716 100644
--- a/linden/indra/llmessage/llhttpassetstorage.cpp
+++ b/linden/indra/llmessage/llhttpassetstorage.cpp
@@ -256,6 +256,10 @@ void LLHTTPAssetRequest::setupCurlHandle()
256 // disable use of proxy, which can't handle chunked transfers 256 // disable use of proxy, which can't handle chunked transfers
257 } 257 }
258 mHTTPHeaders = curl_slist_append(mHTTPHeaders, "Pragma:"); 258 mHTTPHeaders = curl_slist_append(mHTTPHeaders, "Pragma:");
259
260 // bug in curl causes DNS to be cached for too long a time, 0 sets it to never cache DNS results internally (to curl)
261 curl_easy_setopt(mCurlHandle, CURLOPT_DNS_CACHE_TIMEOUT, 0);
262
259 // resist the temptation to explicitly add the Transfer-Encoding: chunked 263 // resist the temptation to explicitly add the Transfer-Encoding: chunked
260 // header here - invokes a libCURL bug 264 // header here - invokes a libCURL bug
261 curl_easy_setopt(mCurlHandle, CURLOPT_HTTPHEADER, mHTTPHeaders); 265 curl_easy_setopt(mCurlHandle, CURLOPT_HTTPHEADER, mHTTPHeaders);
diff --git a/linden/indra/llmessage/llhttpclient.cpp b/linden/indra/llmessage/llhttpclient.cpp
index ef163fa..a07f379 100644
--- a/linden/indra/llmessage/llhttpclient.cpp
+++ b/linden/indra/llmessage/llhttpclient.cpp
@@ -106,7 +106,7 @@ namespace
106 LLSDInjector(const LLSD& sd) : mSD(sd) {} 106 LLSDInjector(const LLSD& sd) : mSD(sd) {}
107 virtual ~LLSDInjector() {} 107 virtual ~LLSDInjector() {}
108 108
109 const char* contentType() { return "application/xml"; } 109 const char* contentType() { return "application/llsd+xml"; }
110 110
111 virtual EStatus process_impl(const LLChannelDescriptors& channels, 111 virtual EStatus process_impl(const LLChannelDescriptors& channels,
112 buffer_ptr_t& buffer, bool& eos, LLSD& context, LLPumpIO* pump) 112 buffer_ptr_t& buffer, bool& eos, LLSD& context, LLPumpIO* pump)
@@ -160,9 +160,10 @@ namespace
160 fstream.seekg(0, std::ios::end); 160 fstream.seekg(0, std::ios::end);
161 U32 fileSize = fstream.tellg(); 161 U32 fileSize = fstream.tellg();
162 fstream.seekg(0, std::ios::beg); 162 fstream.seekg(0, std::ios::beg);
163 std::vector<char> fileBuffer(fileSize); 163 char* fileBuffer;
164 fstream.read(&fileBuffer[0], fileSize); 164 fileBuffer = new char [fileSize];
165 ostream.write(&fileBuffer[0], fileSize); 165 fstream.read(fileBuffer, fileSize);
166 ostream.write(fileBuffer, fileSize);
166 fstream.close(); 167 fstream.close();
167 eos = true; 168 eos = true;
168 return STATUS_DONE; 169 return STATUS_DONE;
@@ -189,9 +190,10 @@ namespace
189 190
190 LLVFile vfile(gVFS, mUUID, mAssetType, LLVFile::READ); 191 LLVFile vfile(gVFS, mUUID, mAssetType, LLVFile::READ);
191 S32 fileSize = vfile.getSize(); 192 S32 fileSize = vfile.getSize();
192 std::vector<U8> fileBuffer(fileSize); 193 U8* fileBuffer;
193 vfile.read(&fileBuffer[0], fileSize); 194 fileBuffer = new U8 [fileSize];
194 ostream.write((char*)&fileBuffer[0], fileSize); 195 vfile.read(fileBuffer, fileSize);
196 ostream.write((char*)fileBuffer, fileSize);
195 eos = true; 197 eos = true;
196 return STATUS_DONE; 198 return STATUS_DONE;
197 } 199 }
@@ -236,7 +238,8 @@ static void request(
236 //the Pragma header it so gratuitously inserts 238 //the Pragma header it so gratuitously inserts
237 //Before inserting the header, force libcurl 239 //Before inserting the header, force libcurl
238 //to not use the proxy (read: llurlrequest.cpp) 240 //to not use the proxy (read: llurlrequest.cpp)
239 if ((iter->first == "Pragma") && (iter->second.asString() == "")) 241 static const std::string PRAGMA("Pragma");
242 if ((iter->first == PRAGMA) && (iter->second.asString().empty()))
240 { 243 {
241 req->useProxy(false); 244 req->useProxy(false);
242 } 245 }
@@ -245,6 +248,19 @@ static void request(
245 req->addHeader(header.str().c_str()); 248 req->addHeader(header.str().c_str());
246 } 249 }
247 } 250 }
251
252 // Check to see if we have already set Accept or not. If no one
253 // set it, set it to application/llsd+xml since that's what we
254 // almost always want.
255 if( method != LLURLRequest::HTTP_PUT && method != LLURLRequest::HTTP_POST )
256 {
257 static const std::string ACCEPT("Accept");
258 if(!headers.has(ACCEPT))
259 {
260 req->addHeader("Accept: application/llsd+xml");
261 }
262 }
263
248 req->setCallback(new LLHTTPClientURLAdaptor(responder)); 264 req->setCallback(new LLHTTPClientURLAdaptor(responder));
249 265
250 if (method == LLURLRequest::HTTP_POST && gMessageSystem) 266 if (method == LLURLRequest::HTTP_POST && gMessageSystem)
@@ -252,12 +268,22 @@ static void request(
252 req->addHeader(llformat("X-SecondLife-UDP-Listen-Port: %d", 268 req->addHeader(llformat("X-SecondLife-UDP-Listen-Port: %d",
253 gMessageSystem->mPort).c_str()); 269 gMessageSystem->mPort).c_str());
254 } 270 }
255 271
256 if (method == LLURLRequest::HTTP_PUT || method == LLURLRequest::HTTP_POST) 272 if (method == LLURLRequest::HTTP_PUT || method == LLURLRequest::HTTP_POST)
257 { 273 {
258 req->addHeader(llformat("Content-Type: %s", 274 static const std::string CONTENT_TYPE("Content-Type");
259 body_injector->contentType()).c_str()); 275 if(!headers.has(CONTENT_TYPE))
260 276 {
277 // If the Content-Type header was passed in, it has
278 // already been added as a header through req->addHeader
279 // in the loop above. We defer to the caller's wisdom, but
280 // if they did not specify a Content-Type, then ask the
281 // injector.
282 req->addHeader(
283 llformat(
284 "Content-Type: %s",
285 body_injector->contentType()).c_str());
286 }
261 chain.push_back(LLIOPipe::ptr_t(body_injector)); 287 chain.push_back(LLIOPipe::ptr_t(body_injector));
262 } 288 }
263 289
@@ -284,9 +310,13 @@ void LLHTTPClient::getByteRange(
284 request(url,LLURLRequest::HTTP_GET, NULL, responder, timeout, headers); 310 request(url,LLURLRequest::HTTP_GET, NULL, responder, timeout, headers);
285} 311}
286 312
287void LLHTTPClient::head(const std::string& url, ResponderPtr responder, const F32 timeout) 313void LLHTTPClient::head(
314 const std::string& url,
315 ResponderPtr responder,
316 const LLSD& headers,
317 const F32 timeout)
288{ 318{
289 request(url, LLURLRequest::HTTP_HEAD, NULL, responder, timeout); 319 request(url, LLURLRequest::HTTP_HEAD, NULL, responder, timeout, headers);
290} 320}
291 321
292void LLHTTPClient::get(const std::string& url, ResponderPtr responder, const LLSD& headers, const F32 timeout) 322void LLHTTPClient::get(const std::string& url, ResponderPtr responder, const LLSD& headers, const F32 timeout)
@@ -397,39 +427,66 @@ LLSD LLHTTPClient::blockingGet(const std::string& url)
397 return response; 427 return response;
398} 428}
399 429
400void LLHTTPClient::put(const std::string& url, const LLSD& body, ResponderPtr responder, const F32 timeout) 430void LLHTTPClient::put(
431 const std::string& url,
432 const LLSD& body,
433 ResponderPtr responder,
434 const LLSD& headers,
435 const F32 timeout)
401{ 436{
402 request(url, LLURLRequest::HTTP_PUT, new LLSDInjector(body), responder, timeout); 437 request(url, LLURLRequest::HTTP_PUT, new LLSDInjector(body), responder, timeout, headers);
403} 438}
404 439
405void LLHTTPClient::post(const std::string& url, const LLSD& body, ResponderPtr responder, const F32 timeout) 440void LLHTTPClient::post(
441 const std::string& url,
442 const LLSD& body,
443 ResponderPtr responder,
444 const LLSD& headers,
445 const F32 timeout)
406{ 446{
407 request(url, LLURLRequest::HTTP_POST, new LLSDInjector(body), responder, timeout); 447 request(url, LLURLRequest::HTTP_POST, new LLSDInjector(body), responder, timeout, headers);
408} 448}
409 449
410void LLHTTPClient::postRaw(const std::string& url, const U8* data, S32 size, ResponderPtr responder, const F32 timeout) 450void LLHTTPClient::postRaw(
451 const std::string& url,
452 const U8* data,
453 S32 size,
454 ResponderPtr responder,
455 const LLSD& headers,
456 const F32 timeout)
411{ 457{
412 request(url, LLURLRequest::HTTP_POST, new RawInjector(data, size), responder, timeout); 458 request(url, LLURLRequest::HTTP_POST, new RawInjector(data, size), responder, timeout, headers);
413} 459}
414 460
415void LLHTTPClient::postFile(const std::string& url, const std::string& filename, ResponderPtr responder, const F32 timeout) 461void LLHTTPClient::postFile(
462 const std::string& url,
463 const std::string& filename,
464 ResponderPtr responder,
465 const LLSD& headers,
466 const F32 timeout)
416{ 467{
417 request(url, LLURLRequest::HTTP_POST, new FileInjector(filename), responder, timeout); 468 request(url, LLURLRequest::HTTP_POST, new FileInjector(filename), responder, timeout, headers);
418} 469}
419 470
420void LLHTTPClient::postFile(const std::string& url, const LLUUID& uuid, 471void LLHTTPClient::postFile(
421 LLAssetType::EType asset_type, ResponderPtr responder, const F32 timeout) 472 const std::string& url,
473 const LLUUID& uuid,
474 LLAssetType::EType asset_type,
475 ResponderPtr responder,
476 const LLSD& headers,
477 const F32 timeout)
422{ 478{
423 request(url, LLURLRequest::HTTP_POST, new VFileInjector(uuid, asset_type), responder, timeout); 479 request(url, LLURLRequest::HTTP_POST, new VFileInjector(uuid, asset_type), responder, timeout, headers);
424} 480}
425 481
426// static 482// static
427void LLHTTPClient::del( 483void LLHTTPClient::del(
428 const std::string& url, 484 const std::string& url,
429 ResponderPtr responder, 485 ResponderPtr responder,
486 const LLSD& headers,
430 const F32 timeout) 487 const F32 timeout)
431{ 488{
432 request(url, LLURLRequest::HTTP_DELETE, NULL, responder, timeout); 489 request(url, LLURLRequest::HTTP_DELETE, NULL, responder, timeout, headers);
433} 490}
434 491
435// static 492// static
@@ -437,9 +494,10 @@ void LLHTTPClient::move(
437 const std::string& url, 494 const std::string& url,
438 const std::string& destination, 495 const std::string& destination,
439 ResponderPtr responder, 496 ResponderPtr responder,
497 const LLSD& hdrs,
440 const F32 timeout) 498 const F32 timeout)
441{ 499{
442 LLSD headers; 500 LLSD headers = hdrs;
443 headers["Destination"] = destination; 501 headers["Destination"] = destination;
444 request(url, LLURLRequest::HTTP_MOVE, NULL, responder, timeout, headers); 502 request(url, LLURLRequest::HTTP_MOVE, NULL, responder, timeout, headers);
445} 503}
diff --git a/linden/indra/llmessage/llhttpclient.h b/linden/indra/llmessage/llhttpclient.h
index 50c6f7a..367098f 100644
--- a/linden/indra/llmessage/llhttpclient.h
+++ b/linden/indra/llmessage/llhttpclient.h
@@ -62,28 +62,56 @@ public:
62 62
63 /** @name non-blocking API */ 63 /** @name non-blocking API */
64 //@{ 64 //@{
65 static void head(const std::string& url, ResponderPtr, const F32 timeout=HTTP_REQUEST_EXPIRY_SECS); 65 static void head(
66 const std::string& url,
67 ResponderPtr,
68 const LLSD& headers = LLSD(),
69 const F32 timeout=HTTP_REQUEST_EXPIRY_SECS);
66 static void getByteRange(const std::string& url, S32 offset, S32 bytes, ResponderPtr, const LLSD& headers=LLSD(), const F32 timeout=HTTP_REQUEST_EXPIRY_SECS); 70 static void getByteRange(const std::string& url, S32 offset, S32 bytes, ResponderPtr, const LLSD& headers=LLSD(), const F32 timeout=HTTP_REQUEST_EXPIRY_SECS);
67 static void get(const std::string& url, ResponderPtr, const LLSD& headers = LLSD(), const F32 timeout=HTTP_REQUEST_EXPIRY_SECS); 71 static void get(const std::string& url, ResponderPtr, const LLSD& headers = LLSD(), const F32 timeout=HTTP_REQUEST_EXPIRY_SECS);
68 static void get(const std::string& url, const LLSD& query, ResponderPtr, const LLSD& headers = LLSD(), const F32 timeout=HTTP_REQUEST_EXPIRY_SECS); 72 static void get(const std::string& url, const LLSD& query, ResponderPtr, const LLSD& headers = LLSD(), const F32 timeout=HTTP_REQUEST_EXPIRY_SECS);
69 73
70 static void put(const std::string& url, const LLSD& body, ResponderPtr, const F32 timeout=HTTP_REQUEST_EXPIRY_SECS); 74 static void put(
75 const std::string& url,
76 const LLSD& body,
77 ResponderPtr,
78 const LLSD& headers = LLSD(),
79 const F32 timeout=HTTP_REQUEST_EXPIRY_SECS);
71 static void getHeaderOnly(const std::string& url, ResponderPtr, const F32 timeout=HTTP_REQUEST_EXPIRY_SECS); 80 static void getHeaderOnly(const std::string& url, ResponderPtr, const F32 timeout=HTTP_REQUEST_EXPIRY_SECS);
72 static void getHeaderOnly(const std::string& url, ResponderPtr, const LLSD& headers, const F32 timeout=HTTP_REQUEST_EXPIRY_SECS); 81 static void getHeaderOnly(const std::string& url, ResponderPtr, const LLSD& headers, const F32 timeout=HTTP_REQUEST_EXPIRY_SECS);
73 82
74 static void post(const std::string& url, const LLSD& body, ResponderPtr, const F32 timeout=HTTP_REQUEST_EXPIRY_SECS); 83 static void post(
75 84 const std::string& url,
85 const LLSD& body,
86 ResponderPtr,
87 const LLSD& headers = LLSD(),
88 const F32 timeout=HTTP_REQUEST_EXPIRY_SECS);
76 /** Takes ownership of data and deletes it when sent */ 89 /** Takes ownership of data and deletes it when sent */
77 static void postRaw(const std::string& url, const U8* data, S32 size, ResponderPtr responder, const F32 timeout=HTTP_REQUEST_EXPIRY_SECS); 90 static void postRaw(
78 91 const std::string& url,
79 static void postFile(const std::string& url, const std::string& filename, ResponderPtr, const F32 timeout=HTTP_REQUEST_EXPIRY_SECS); 92 const U8* data,
80 # 93 S32 size,
81 static void postFile(const std::string& url, const LLUUID& uuid, 94 ResponderPtr responder,
82 LLAssetType::EType asset_type, ResponderPtr responder, const F32 timeout=HTTP_REQUEST_EXPIRY_SECS); 95 const LLSD& headers = LLSD(),
96 const F32 timeout=HTTP_REQUEST_EXPIRY_SECS);
97 static void postFile(
98 const std::string& url,
99 const std::string& filename,
100 ResponderPtr,
101 const LLSD& headers = LLSD(),
102 const F32 timeout=HTTP_REQUEST_EXPIRY_SECS);
103 static void postFile(
104 const std::string& url,
105 const LLUUID& uuid,
106 LLAssetType::EType asset_type,
107 ResponderPtr responder,
108 const LLSD& headers = LLSD(),
109 const F32 timeout=HTTP_REQUEST_EXPIRY_SECS);
83 110
84 static void del( 111 static void del(
85 const std::string& url, 112 const std::string& url,
86 ResponderPtr responder, 113 ResponderPtr responder,
114 const LLSD& headers = LLSD(),
87 const F32 timeout=HTTP_REQUEST_EXPIRY_SECS); 115 const F32 timeout=HTTP_REQUEST_EXPIRY_SECS);
88 ///< sends a DELETE method, but we can't call it delete in c++ 116 ///< sends a DELETE method, but we can't call it delete in c++
89 117
@@ -93,12 +121,14 @@ public:
93 * @param url The complete serialized (and escaped) url to get. 121 * @param url The complete serialized (and escaped) url to get.
94 * @param destination The complete serialized destination url. 122 * @param destination The complete serialized destination url.
95 * @param responder The responder that will handle the result. 123 * @param responder The responder that will handle the result.
124 * @param headers A map of key:value headers to pass to the request
96 * @param timeout The number of seconds to give the server to respond. 125 * @param timeout The number of seconds to give the server to respond.
97 */ 126 */
98 static void move( 127 static void move(
99 const std::string& url, 128 const std::string& url,
100 const std::string& destination, 129 const std::string& destination,
101 ResponderPtr responder, 130 ResponderPtr responder,
131 const LLSD& headers = LLSD(),
102 const F32 timeout=HTTP_REQUEST_EXPIRY_SECS); 132 const F32 timeout=HTTP_REQUEST_EXPIRY_SECS);
103 133
104 //@} 134 //@}
diff --git a/linden/indra/llmessage/lliohttpserver.cpp b/linden/indra/llmessage/lliohttpserver.cpp
index d4155f6..64222ff 100644
--- a/linden/indra/llmessage/lliohttpserver.cpp
+++ b/linden/indra/llmessage/lliohttpserver.cpp
@@ -47,6 +47,7 @@
47#include "llpumpio.h" 47#include "llpumpio.h"
48#include "llsd.h" 48#include "llsd.h"
49#include "llsdserialize_xml.h" 49#include "llsdserialize_xml.h"
50#include "llstat.h"
50#include "llstl.h" 51#include "llstl.h"
51#include "lltimer.h" 52#include "lltimer.h"
52 53
@@ -171,22 +172,26 @@ LLIOPipe::EStatus LLHTTPPipe::process_impl(
171 std::string verb = context[CONTEXT_REQUEST][CONTEXT_VERB]; 172 std::string verb = context[CONTEXT_REQUEST][CONTEXT_VERB];
172 if(verb == HTTP_VERB_GET) 173 if(verb == HTTP_VERB_GET)
173 { 174 {
175 LLPerfBlock getblock("http_get");
174 mNode.get(LLHTTPNode::ResponsePtr(mResponse), context); 176 mNode.get(LLHTTPNode::ResponsePtr(mResponse), context);
175 } 177 }
176 else if(verb == HTTP_VERB_PUT) 178 else if(verb == HTTP_VERB_PUT)
177 { 179 {
180 LLPerfBlock putblock("http_put");
178 LLSD input; 181 LLSD input;
179 LLSDSerialize::fromXML(input, istr); 182 LLSDSerialize::fromXML(input, istr);
180 mNode.put(LLHTTPNode::ResponsePtr(mResponse), context, input); 183 mNode.put(LLHTTPNode::ResponsePtr(mResponse), context, input);
181 } 184 }
182 else if(verb == HTTP_VERB_POST) 185 else if(verb == HTTP_VERB_POST)
183 { 186 {
187 LLPerfBlock postblock("http_post");
184 LLSD input; 188 LLSD input;
185 LLSDSerialize::fromXML(input, istr); 189 LLSDSerialize::fromXML(input, istr);
186 mNode.post(LLHTTPNode::ResponsePtr(mResponse), context, input); 190 mNode.post(LLHTTPNode::ResponsePtr(mResponse), context, input);
187 } 191 }
188 else if(verb == HTTP_VERB_DELETE) 192 else if(verb == HTTP_VERB_DELETE)
189 { 193 {
194 LLPerfBlock delblock("http_delete");
190 mNode.del(LLHTTPNode::ResponsePtr(mResponse), context); 195 mNode.del(LLHTTPNode::ResponsePtr(mResponse), context);
191 } 196 }
192 else if(verb == HTTP_VERB_OPTIONS) 197 else if(verb == HTTP_VERB_OPTIONS)
@@ -240,7 +245,7 @@ LLIOPipe::EStatus LLHTTPPipe::process_impl(
240 case STATE_GOOD_RESULT: 245 case STATE_GOOD_RESULT:
241 { 246 {
242 LLSD headers = mHeaders; 247 LLSD headers = mHeaders;
243 headers["Content-Type"] = "application/xml"; 248 headers["Content-Type"] = "application/llsd+xml";
244 context[CONTEXT_RESPONSE][CONTEXT_HEADERS] = headers; 249 context[CONTEXT_RESPONSE][CONTEXT_HEADERS] = headers;
245 LLBufferStream ostr(channels, buffer.get()); 250 LLBufferStream ostr(channels, buffer.get());
246 LLSDSerialize::toXML(mGoodResult, ostr); 251 LLSDSerialize::toXML(mGoodResult, ostr);
diff --git a/linden/indra/llmessage/llmail.cpp b/linden/indra/llmessage/llmail.cpp
index 8ae7206..0504080 100644
--- a/linden/indra/llmessage/llmail.cpp
+++ b/linden/indra/llmessage/llmail.cpp
@@ -51,6 +51,7 @@
51#include "llblowfishcipher.h" 51#include "llblowfishcipher.h"
52#include "llerror.h" 52#include "llerror.h"
53#include "llhost.h" 53#include "llhost.h"
54#include "llsd.h"
54#include "llstring.h" 55#include "llstring.h"
55#include "lluuid.h" 56#include "lluuid.h"
56#include "net.h" 57#include "net.h"
@@ -111,16 +112,22 @@ void disconnect_smtp()
111// Returns TRUE on success. 112// Returns TRUE on success.
112// message should NOT be SMTP escaped. 113// message should NOT be SMTP escaped.
113// static 114// static
114BOOL LLMail::send(const char* from_name, const char* from_address, 115BOOL LLMail::send(
115 const char* to_name, const char* to_address, 116 const char* from_name,
116 const char* subject, const char* message) 117 const char* from_address,
118 const char* to_name,
119 const char* to_address,
120 const char* subject,
121 const char* message,
122 const LLSD& headers)
117{ 123{
118 std::string header = buildSMTPTransaction( 124 std::string header = buildSMTPTransaction(
119 from_name, 125 from_name,
120 from_address, 126 from_address,
121 to_name, 127 to_name,
122 to_address, 128 to_address,
123 subject); 129 subject,
130 headers);
124 if(header.empty()) 131 if(header.empty())
125 { 132 {
126 return FALSE; 133 return FALSE;
@@ -192,7 +199,8 @@ std::string LLMail::buildSMTPTransaction(
192 const char* from_address, 199 const char* from_address,
193 const char* to_name, 200 const char* to_name,
194 const char* to_address, 201 const char* to_address,
195 const char* subject) 202 const char* subject,
203 const LLSD& headers)
196{ 204{
197 if(!from_address || !to_address) 205 if(!from_address || !to_address)
198 { 206 {
@@ -236,8 +244,20 @@ std::string LLMail::buildSMTPTransaction(
236 << "DATA\r\n" 244 << "DATA\r\n"
237 << "From: " << from_fmt.str() << "\r\n" 245 << "From: " << from_fmt.str() << "\r\n"
238 << "To: " << to_fmt.str() << "\r\n" 246 << "To: " << to_fmt.str() << "\r\n"
239 << "Subject: " << subject << "\r\n" 247 << "Subject: " << subject << "\r\n";
240 << "\r\n"; 248
249 if(headers.isMap())
250 {
251 LLSD::map_const_iterator iter = headers.beginMap();
252 LLSD::map_const_iterator end = headers.endMap();
253 for(; iter != end; ++iter)
254 {
255 header << (*iter).first << ": " << ((*iter).second).asString()
256 << "\r\n";
257 }
258 }
259
260 header << "\r\n";
241 return header.str(); 261 return header.str();
242} 262}
243 263
diff --git a/linden/indra/llmessage/llmail.h b/linden/indra/llmessage/llmail.h
index 86b7793..018e180 100644
--- a/linden/indra/llmessage/llmail.h
+++ b/linden/indra/llmessage/llmail.h
@@ -34,7 +34,7 @@
34 34
35typedef struct apr_pool_t apr_pool_t; 35typedef struct apr_pool_t apr_pool_t;
36 36
37class LLUUID; 37#include "llsd.h"
38 38
39class LLMail 39class LLMail
40{ 40{
@@ -45,34 +45,51 @@ public:
45 // Allow all email transmission to be disabled/enabled. 45 // Allow all email transmission to be disabled/enabled.
46 static void enable(bool mail_enabled); 46 static void enable(bool mail_enabled);
47 47
48 // returns TRUE if the call succeeds, FALSE otherwise. 48 /**
49 // 49 * @brief send an email
50 // Results in: 50 * @param from_name The name of the email sender
51 // From: "from_name" <from_address> 51 * @param from_address The email address for the sender
52 // To: "to_name" <to_address> 52 * @param to_name The name of the email recipient
53 // Subject: subject 53 * @param to_address The email recipient address
54 // message 54 * @param subject The subject of the email
55 static BOOL send(const char* from_name, const char* from_address, 55 * @param headers optional X-Foo headers in an llsd map.
56 const char* to_name, const char* to_address, 56 * @return Returns TRUE if the call succeeds, FALSE otherwise.
57 const char* subject, const char* message); 57 *
58 * Results in:
59 * From: "from_name" <from_address>
60 * To: "to_name" <to_address>
61 * Subject: subject
62 *
63 * message
64 */
65 static BOOL send(
66 const char* from_name,
67 const char* from_address,
68 const char* to_name,
69 const char* to_address,
70 const char* subject,
71 const char* message,
72 const LLSD& headers = LLSD());
58 73
59 /** 74 /**
60 * @brief build the complete smtp transaction & header for use in an 75 * @brief build the complete smtp transaction & header for use in an
61 * mail. 76 * mail.
62 * 77 *
63 * @param from_name The name of the email sender 78 * @param from_name The name of the email sender
64 * @param from_address The email address for the sender 79 * @param from_address The email address for the sender
65 * @param to_name The name of the email recipient 80 * @param to_name The name of the email recipient
66 * @param to_name The email recipient address 81 * @param to_address The email recipient address
67 * @param subject The subject of the email 82 * @param subject The subject of the email
68 * @return Returns the complete SMTP transaction mail header. 83 * @param headers optional X-Foo headers in an llsd map.
69 */ 84 * @return Returns the complete SMTP transaction mail header.
85 */
70 static std::string buildSMTPTransaction( 86 static std::string buildSMTPTransaction(
71 const char* from_name, 87 const char* from_name,
72 const char* from_address, 88 const char* from_address,
73 const char* to_name, 89 const char* to_name,
74 const char* to_address, 90 const char* to_address,
75 const char* subject); 91 const char* subject,
92 const LLSD& headers = LLSD());
76 93
77 /** 94 /**
78 * @brief send an email with header and body. 95 * @brief send an email with header and body.
diff --git a/linden/indra/llmessage/llmessagetemplate.cpp b/linden/indra/llmessage/llmessagetemplate.cpp
index 4a560ca..ff44d45 100644
--- a/linden/indra/llmessage/llmessagetemplate.cpp
+++ b/linden/indra/llmessage/llmessagetemplate.cpp
@@ -50,7 +50,7 @@ void LLMsgVarData::addData(const void *data, S32 size, EMsgVariableType type, S3
50 } 50 }
51 if(size) 51 if(size)
52 { 52 {
53 delete mData; // Delete it if it already exists 53 delete[] mData; // Delete it if it already exists
54 mData = new U8[size]; 54 mData = new U8[size];
55 htonmemcpy(mData, data, mType, size); 55 htonmemcpy(mData, data, mType, size);
56 } 56 }
@@ -175,3 +175,23 @@ std::ostream& operator<<(std::ostream& s, LLMessageTemplate &msg)
175 175
176 return s; 176 return s;
177} 177}
178
179void LLMessageTemplate::banUdp()
180{
181 static const char* deprecation[] = {
182 "NotDeprecated",
183 "Deprecated",
184 "UDPDeprecated",
185 "UDPBlackListed"
186 };
187 if (mDeprecation != MD_DEPRECATED)
188 {
189 llinfos << "Setting " << mName << " to UDPBlackListed was " << deprecation[mDeprecation] << llendl;
190 mDeprecation = MD_UDPBLACKLISTED;
191 }
192 else
193 {
194 llinfos << mName << " is already more deprecated than UDPBlackListed" << llendl;
195 }
196}
197
diff --git a/linden/indra/llmessage/llmessagetemplate.h b/linden/indra/llmessage/llmessagetemplate.h
index 716c618..445d1a8 100644
--- a/linden/indra/llmessage/llmessagetemplate.h
+++ b/linden/indra/llmessage/llmessagetemplate.h
@@ -34,6 +34,7 @@
34 34
35#include "lldarray.h" 35#include "lldarray.h"
36#include "message.h" // TODO: babbage: Remove... 36#include "message.h" // TODO: babbage: Remove...
37#include "llstat.h"
37#include "llstl.h" 38#include "llstl.h"
38 39
39class LLMsgVarData 40class LLMsgVarData
@@ -370,20 +371,23 @@ public:
370 { 371 {
371 if (mHandlerFunc) 372 if (mHandlerFunc)
372 { 373 {
374 LLPerfBlock msg_cb_time("msg_cb", mName);
373 mHandlerFunc(msgsystem, mUserData); 375 mHandlerFunc(msgsystem, mUserData);
374 return TRUE; 376 return TRUE;
375 } 377 }
376 return FALSE; 378 return FALSE;
377 } 379 }
378 380
379 bool isBanned(bool trustedSource) const 381 bool isUdpBanned() const
380 { 382 {
381 return trustedSource ? mBanFromTrusted : mBanFromUntrusted; 383 return mDeprecation == MD_UDPBLACKLISTED;
382 } 384 }
383 385
384 bool isUdpBanned() const 386 void banUdp();
387
388 bool isBanned(bool trustedSource) const
385 { 389 {
386 return mDeprecation == MD_UDPBLACKLISTED; 390 return trustedSource ? mBanFromTrusted : mBanFromUntrusted;
387 } 391 }
388 392
389 friend std::ostream& operator<<(std::ostream& s, LLMessageTemplate &msg); 393 friend std::ostream& operator<<(std::ostream& s, LLMessageTemplate &msg);
diff --git a/linden/indra/llmessage/llmessagethrottle.cpp b/linden/indra/llmessage/llmessagethrottle.cpp
index ad9df26..47e1bd6 100644
--- a/linden/indra/llmessage/llmessagethrottle.cpp
+++ b/linden/indra/llmessage/llmessagethrottle.cpp
@@ -119,7 +119,7 @@ BOOL LLMessageThrottle::addViewerAlert(const LLUUID& to, const std::string& mesg
119 full_mesg << to << mesg; 119 full_mesg << to << mesg;
120 120
121 // Create an entry for this message. 121 // Create an entry for this message.
122 size_t hash = llhash<const char*> (full_mesg.str().c_str()); 122 size_t hash = llhash(full_mesg.str().c_str());
123 LLMessageThrottleEntry entry(hash, LLFrameTimer::getTotalTime()); 123 LLMessageThrottleEntry entry(hash, LLFrameTimer::getTotalTime());
124 124
125 // Check if this message is already in the list. 125 // Check if this message is already in the list.
@@ -153,7 +153,7 @@ BOOL LLMessageThrottle::addAgentAlert(const LLUUID& agent, const LLUUID& task, c
153 full_mesg << agent << task << mesg; 153 full_mesg << agent << task << mesg;
154 154
155 // Create an entry for this message. 155 // Create an entry for this message.
156 size_t hash = llhash<const char*> (full_mesg.str().c_str()); 156 size_t hash = llhash(full_mesg.str().c_str());
157 LLMessageThrottleEntry entry(hash, LLFrameTimer::getTotalTime()); 157 LLMessageThrottleEntry entry(hash, LLFrameTimer::getTotalTime());
158 158
159 // Check if this message is already in the list. 159 // Check if this message is already in the list.
diff --git a/linden/indra/llmessage/llnamevalue.cpp b/linden/indra/llmessage/llnamevalue.cpp
index c44f6ce..f661261 100644
--- a/linden/indra/llmessage/llnamevalue.cpp
+++ b/linden/indra/llmessage/llnamevalue.cpp
@@ -896,7 +896,7 @@ void LLNameValue::setVec3(const LLVector3 &a)
896} 896}
897 897
898 898
899std::string LLNameValue::printNameValue() 899std::string LLNameValue::printNameValue() const
900{ 900{
901 std::string buffer; 901 std::string buffer;
902 buffer = llformat("%s %s %s %s ", mName, mStringType, mStringClass, mStringSendto); 902 buffer = llformat("%s %s %s %s ", mName, mStringType, mStringClass, mStringSendto);
@@ -905,7 +905,7 @@ std::string LLNameValue::printNameValue()
905 return buffer; 905 return buffer;
906} 906}
907 907
908std::string LLNameValue::printData() 908std::string LLNameValue::printData() const
909{ 909{
910 std::string buffer; 910 std::string buffer;
911 switch(mType) 911 switch(mType)
diff --git a/linden/indra/llmessage/llnamevalue.h b/linden/indra/llmessage/llnamevalue.h
index 52beb07..f6c5040 100644
--- a/linden/indra/llmessage/llnamevalue.h
+++ b/linden/indra/llmessage/llnamevalue.h
@@ -148,8 +148,8 @@ public:
148 BOOL sendToViewer() const; 148 BOOL sendToViewer() const;
149 149
150 void callCallback(); 150 void callCallback();
151 std::string printNameValue(); 151 std::string printNameValue() const;
152 std::string printData(); 152 std::string printData() const;
153 153
154 ENameValueType getTypeEnum() const { return mType; } 154 ENameValueType getTypeEnum() const { return mType; }
155 ENameValueClass getClassEnum() const { return mClass; } 155 ENameValueClass getClassEnum() const { return mClass; }
diff --git a/linden/indra/llmessage/llpumpio.cpp b/linden/indra/llmessage/llpumpio.cpp
index 6adf9c2..9ce0bab 100644
--- a/linden/indra/llmessage/llpumpio.cpp
+++ b/linden/indra/llmessage/llpumpio.cpp
@@ -41,6 +41,7 @@
41#include "llapr.h" 41#include "llapr.h"
42#include "llmemtype.h" 42#include "llmemtype.h"
43#include "llstl.h" 43#include "llstl.h"
44#include "llstat.h"
44 45
45// These should not be enabled in production, but they can be 46// These should not be enabled in production, but they can be
46// intensely useful during development for finding certain kinds of 47// intensely useful during development for finding certain kinds of
@@ -521,7 +522,10 @@ void LLPumpIO::pump(const S32& poll_timeout)
521 //llinfos << "polling" << llendl; 522 //llinfos << "polling" << llendl;
522 S32 count = 0; 523 S32 count = 0;
523 S32 client_id = 0; 524 S32 client_id = 0;
524 apr_pollset_poll(mPollset, poll_timeout, &count, &poll_fd); 525 {
526 LLPerfBlock polltime("pump_poll");
527 apr_pollset_poll(mPollset, poll_timeout, &count, &poll_fd);
528 }
525 PUMP_DEBUG; 529 PUMP_DEBUG;
526 for(S32 ii = 0; ii < count; ++ii) 530 for(S32 ii = 0; ii < count; ++ii)
527 { 531 {
diff --git a/linden/indra/llmessage/llregionflags.h b/linden/indra/llmessage/llregionflags.h
index af010ae..46624c1 100644
--- a/linden/indra/llmessage/llregionflags.h
+++ b/linden/indra/llmessage/llregionflags.h
@@ -60,8 +60,10 @@ const U32 REGION_FLAGS_BLOCK_LAND_RESELL = (1 << 7);
60// All content wiped once per night 60// All content wiped once per night
61const U32 REGION_FLAGS_SANDBOX = (1 << 8); 61const U32 REGION_FLAGS_SANDBOX = (1 << 8);
62const U32 REGION_FLAGS_NULL_LAYER = (1 << 9); 62const U32 REGION_FLAGS_NULL_LAYER = (1 << 9);
63const U32 REGION_FLAGS_SKIP_AGENT_ACTION = (1 << 10); 63// const U32 REGION_FLAGS_SKIP_AGENT_ACTION = (1 << 10);
64const U32 REGION_FLAGS_SKIP_UPDATE_INTEREST_LIST= (1 << 11); 64const U32 REGION_FLAGS_HARD_ALLOW_LAND_TRANSFER = (1 << 10); // Region allows land reselling
65// const U32 REGION_FLAGS_SKIP_UPDATE_INTEREST_LIST= (1 << 11);
66const U32 REGION_FLAGS_HARD_ALLOW_POST_CLASSIFIED = (1 << 11); // Region allows posting of classified ads
65const U32 REGION_FLAGS_SKIP_COLLISIONS = (1 << 12); // Pin all non agent rigid bodies 67const U32 REGION_FLAGS_SKIP_COLLISIONS = (1 << 12); // Pin all non agent rigid bodies
66const U32 REGION_FLAGS_SKIP_SCRIPTS = (1 << 13); 68const U32 REGION_FLAGS_SKIP_SCRIPTS = (1 << 13);
67const U32 REGION_FLAGS_SKIP_PHYSICS = (1 << 14); // Skip all physics 69const U32 REGION_FLAGS_SKIP_PHYSICS = (1 << 14); // Skip all physics
diff --git a/linden/indra/llmessage/message.cpp b/linden/indra/llmessage/message.cpp
index b20731a..3ee3c03 100644
--- a/linden/indra/llmessage/message.cpp
+++ b/linden/indra/llmessage/message.cpp
@@ -3956,22 +3956,27 @@ void LLMessageSystem::getString(const char *block, const char *var,
3956 blocknum); 3956 blocknum);
3957} 3957}
3958 3958
3959S32 LLMessageSystem::getNumberOfBlocksFast(const char *blockname) 3959BOOL LLMessageSystem::has(const char *blockname) const
3960{
3961 return getNumberOfBlocks(blockname) > 0;
3962}
3963
3964S32 LLMessageSystem::getNumberOfBlocksFast(const char *blockname) const
3960{ 3965{
3961 return mMessageReader->getNumberOfBlocks(blockname); 3966 return mMessageReader->getNumberOfBlocks(blockname);
3962} 3967}
3963 3968
3964S32 LLMessageSystem::getNumberOfBlocks(const char *blockname) 3969S32 LLMessageSystem::getNumberOfBlocks(const char *blockname) const
3965{ 3970{
3966 return getNumberOfBlocksFast(LLMessageStringTable::getInstance()->getString(blockname)); 3971 return getNumberOfBlocksFast(LLMessageStringTable::getInstance()->getString(blockname));
3967} 3972}
3968 3973
3969S32 LLMessageSystem::getSizeFast(const char *blockname, const char *varname) 3974S32 LLMessageSystem::getSizeFast(const char *blockname, const char *varname) const
3970{ 3975{
3971 return mMessageReader->getSize(blockname, varname); 3976 return mMessageReader->getSize(blockname, varname);
3972} 3977}
3973 3978
3974S32 LLMessageSystem::getSize(const char *blockname, const char *varname) 3979S32 LLMessageSystem::getSize(const char *blockname, const char *varname) const
3975{ 3980{
3976 return getSizeFast(LLMessageStringTable::getInstance()->getString(blockname), 3981 return getSizeFast(LLMessageStringTable::getInstance()->getString(blockname),
3977 LLMessageStringTable::getInstance()->getString(varname)); 3982 LLMessageStringTable::getInstance()->getString(varname));
@@ -3979,13 +3984,13 @@ S32 LLMessageSystem::getSize(const char *blockname, const char *varname)
3979 3984
3980// size in bytes of variable length data 3985// size in bytes of variable length data
3981S32 LLMessageSystem::getSizeFast(const char *blockname, S32 blocknum, 3986S32 LLMessageSystem::getSizeFast(const char *blockname, S32 blocknum,
3982 const char *varname) 3987 const char *varname) const
3983{ 3988{
3984 return mMessageReader->getSize(blockname, blocknum, varname); 3989 return mMessageReader->getSize(blockname, blocknum, varname);
3985} 3990}
3986 3991
3987S32 LLMessageSystem::getSize(const char *blockname, S32 blocknum, 3992S32 LLMessageSystem::getSize(const char *blockname, S32 blocknum,
3988 const char *varname) 3993 const char *varname) const
3989{ 3994{
3990 return getSizeFast(LLMessageStringTable::getInstance()->getString(blockname), blocknum, 3995 return getSizeFast(LLMessageStringTable::getInstance()->getString(blockname), blocknum,
3991 LLMessageStringTable::getInstance()->getString(varname)); 3996 LLMessageStringTable::getInstance()->getString(varname));
@@ -4021,3 +4026,18 @@ bool LLMessageSystem::checkAllMessages(S64 frame_count, LLPumpIO* http_pump)
4021 http_pump->callback(); 4026 http_pump->callback();
4022 return (mPacketsIn - packetsIn) > 0; 4027 return (mPacketsIn - packetsIn) > 0;
4023} 4028}
4029
4030void LLMessageSystem::banUdpMessage(const std::string& name)
4031{
4032 message_template_name_map_t::iterator itt = mMessageTemplates.find(
4033 LLMessageStringTable::getInstance()->getString(name.c_str())
4034 );
4035 if(itt != mMessageTemplates.end())
4036 {
4037 itt->second->banUdp();
4038 }
4039 else
4040 {
4041 llwarns << "Attempted to ban an unknown message: " << name << "." << llendl;
4042 }
4043}
diff --git a/linden/indra/llmessage/message.h b/linden/indra/llmessage/message.h
index 8807521..b72aa9a 100644
--- a/linden/indra/llmessage/message.h
+++ b/linden/indra/llmessage/message.h
@@ -562,6 +562,9 @@ public:
562 /** Return false true if name is unknown or trusted */ 562 /** Return false true if name is unknown or trusted */
563 bool isUntrustedMessage(const std::string& name) const; 563 bool isUntrustedMessage(const std::string& name) const;
564 564
565 // Change this message to be UDP black listed.
566 void banUdpMessage(const std::string& name);
567
565private: 568private:
566 // A list of the circuits that need to be sent DenyTrustedCircuit messages. 569 // A list of the circuits that need to be sent DenyTrustedCircuit messages.
567 typedef std::set<LLHost> host_set_t; 570 typedef std::set<LLHost> host_set_t;
@@ -591,13 +594,14 @@ public:
591 LLHost findHost(const U32 circuit_code); 594 LLHost findHost(const U32 circuit_code);
592 void sanityCheck(); 595 void sanityCheck();
593 596
594 S32 getNumberOfBlocksFast(const char *blockname); 597 BOOL has(const char *blockname) const;
595 S32 getNumberOfBlocks(const char *blockname); 598 S32 getNumberOfBlocksFast(const char *blockname) const;
596 S32 getSizeFast(const char *blockname, const char *varname); 599 S32 getNumberOfBlocks(const char *blockname) const;
597 S32 getSize(const char *blockname, const char *varname); 600 S32 getSizeFast(const char *blockname, const char *varname) const;
601 S32 getSize(const char *blockname, const char *varname) const;
598 S32 getSizeFast(const char *blockname, S32 blocknum, 602 S32 getSizeFast(const char *blockname, S32 blocknum,
599 const char *varname); // size in bytes of data 603 const char *varname) const; // size in bytes of data
600 S32 getSize(const char *blockname, S32 blocknum, const char *varname); 604 S32 getSize(const char *blockname, S32 blocknum, const char *varname) const;
601 605
602 void resetReceiveCounts(); // resets receive counts for all message types to 0 606 void resetReceiveCounts(); // resets receive counts for all message types to 0
603 void dumpReceiveCounts(); // dumps receive count for each message type to llinfos 607 void dumpReceiveCounts(); // dumps receive count for each message type to llinfos