[reSIProcate] stuff not in 1.8 branch
I notice various things have changed on main but are not in the 1.8
branch for 1.8.5
svn diff \
https://svn.resiprocate.org/rep/resiprocate/branches/resiprocate-1.8 \
https://svn.resiprocate.org/rep/resiprocate/main
I've attached a diff between the branches, here is a summary of the
files that are involved:
ChangeLog
reSIProcate_8_0.sln
resip/dum/RegistrationHandler.hxx
resip/stack/Token.cxx
resip/stack/ParameterHash.gperf
resip/stack/ParameterTypes.hxx
resip/stack/ParameterTypeEnums.hxx
resip/stack/TransportSelector.cxx
resip/stack/gperf_w32.bat
resip/stack/ParameterTypes.cxx
resip/stack/ParameterHash.cxx
resip/stack/Token.hxx
reSIProcate_9_0.sln
repro/VERSION
repro/reprolib_8_0.vcproj
repro/WebAdmin.cxx
repro/Registrar.cxx
repro/ResponseContext.cxx
repro/AccountingCollector.hxx
repro/PersistentMessageQueue.cxx
repro/Proxy.cxx
repro/monkeys/StrictRouteFixup.cxx
repro/monkeys/GeoProximityTargetSorter.cxx
repro/monkeys/GeoProximityTargetSorter.hxx
repro/monkeys/CertificateAuthenticator.hxx
repro/monkeys/AmIResponsible.cxx
repro/reprolib_9_0.vcproj
repro/repro.config
repro/RequestContext.cxx
repro/ReproRunner.cxx
repro/reprolib_10_0.vcxproj
repro/reprolib_10_0.vcxproj.filters
repro/AccountingCollector.cxx
repro/Registrar.hxx
repro/reprocmd/reprocmd.cpp
repro/PersistentMessageQueue.hxx
repro/Proxy.hxx
repro/accountingconsumers/queuetostream_10_0.vcxproj.filters
repro/accountingconsumers/queuetostream.cpp
repro/accountingconsumers/Makefile.am
repro/accountingconsumers/queuetostream_10_0.vcxproj
repro/accountingconsumers/queuetostream_9_0.vcproj
repro/RequestContext.hxx
repro/Makefile.am
reSIProcate_10_0.sln
rutil/cajun/ReleaseNotes.txt
rutil/cajun/json/elements.h
rutil/cajun/json/writer.h
rutil/cajun/json/reader.inl
rutil/cajun/json/visitor.h
rutil/cajun/json/reader.h
rutil/cajun/json/elements.inl
rutil/cajun/json/writer.inl
rutil/cajun/Readme.txt
rutil/TimeLimitFifo.hxx
rutil/WinCompat.hxx
rutil/FileSystem.cxx
rutil/WinCompat.cxx
rutil/FileSystem.hxx
rutil/Makefile.am
configure.ac
Index: ChangeLog
===================================================================
--- ChangeLog (.../branches/resiprocate-1.8) (revision 9855)
+++ ChangeLog (.../main) (revision 9855)
@@ -1,340 +0,0 @@
-= Release Notes v 1.8 =
-
-==General==
-===New features===
-*added new REND project for for Registration and Presence load testing
-
-
-==Build system==
-===New features===
-*the old build system was completely replaced with an autotools build system
-*many components are now optional and must be enabled at configure time
-*autotools dist functionality now used to produce official release tarball
-*libtool now sets SONAME using the release number convention
-*resip now builds on Solaris SunPro (tested with third-party libs from OpenCSW)
-*update BerkeleyDb to 4.8 in contrib
-*added MaxMind GeoIP library to contrib
-*added MySQL client connector library to contrib
-*allow resip's asio drop to build with OpenSSL 1.0 and above
-*allow testStack to use popt for VS2010 projects
-
-===Bug fixes===
-*fixed many compilation errors and warnings on various platforms
-
-
-==rutil==
-===New features===
-*added Timer::resetT1 to make it easier to tweak T1
-*added ConfigParse class to aid with configuration file and command line parsing
-*Data class enhancements
-**made Data class smaller, without sacrificing functionality. Data is 20 (56 vs 36) bytes smaller on 64-bit libs, and 4 (36 vs 32) bytes smaller on 32-bit libs.
-**several very simple functions have been inlined.
-**Data::md5() has been changed to Data::md5(Data::EncodingType type=HEX); this allows the output of md5() to be encoded as hex or Base64, or not encoded at all (binary).
-**Data::replace(const Data& match, const Data& target) has been updated to Data::replace(const Data& match, const Data& target, int max=INT_MAX); this allows the maximum number of replacements to be specified.
-**specialized hashing and comparison functions have been added:
-***Data::caseInsensitiveTokenHash(); this is a case-insensitive hash that assumes that the Data is an RFC 3261 token (eg; branch params). This hash function is based on the Hsieh hash.
-***bool Data::caseInsensitiveTokenCompare(const Data& rhs); this is an equality comparison that assumes that both Datas are RFC 3261 tokens (eg; branch parameters) and is faster than strncasecmp().
-**Data& schemeLowercase(); this is an optimized variant of lowercase() that assumes the Data is an RFC 3261 scheme.
-*performance improvements to ParseBuffer
-**most functions that returned a Pointer now return a much more lightweight CurrentPosition object.
-**allow some of the simpler functions to be inlined
-**integer parsing code is more efficient, and overflow detection is better
-*performance enhancements to DnsUtil
-**DnsUtil::inet_ntop(): For some reason, the stock system inet_ntop is dreadfully inefficient on OS X. A dirt-simple hand-rolled implementation was 5-6 times as fast. This is shocking. The Linux implementation is plenty efficient, though, so we're using preprocessor to activate the hand-rolled code.
-**DnsUtil::isIpV4Address(): The implementation uses sscanf(), which is pretty expensive. Hand-rolled some code that is much faster.
-*moved XMLCursor class from resip/stack to rutil
-*custom ares build was moved from /contrib/ares to /rutil/dns/ares, since it is a heavily customize version of the ares library - building with c-ares as an alternative is still possible
-*added new ServerProcess class to encapsulate method for daemonizing and other server/daemon requirements like PID files
-*added new KeyValueStore class for highly efficient generic storage
-**keys are simple integer indexes into a vector and must be allocated before they are used
-**currently supports storage and retrieval of the following types: Data, bool, short, unsigned short, int, unsigned int, and UInt64
-*added Inserter functionality for collections that store pointers to items. Use InserterP instead of Inserter for such collections.
-
-===Bug fixes===
-*fixed a Windows API issue with ThreadLocalStorage. The Windows API functions for TLS do not guarantee that the id / index number will be less than 1088. Change the code to use a std::map<DWORD> instead of a fixed size array. The previous code would cause heap corruption if the OS passed back an index number of 1088.
-*fixed a bad assert in Random class - we shouldn't be using RAND_MAX to look at what is returned by random()
-*fix bug in Data. If Data is wrapping memory allocated externally (ie. Share mode = BORROW) and you start appending to it. It is possible that the append method will write a NULL character off the end of the buffer. Changed the resize condition to make the buffer larger 1 character sooner, to accommodate for this.
-*fix for IPv6 - If localhost is used at init time, then IP family wasn't properly populated in ares
-*fix for IPv6 - If DNS servers are reached over IPv6, then they were not printed to the logs correctly
-
-
-==stack==
-===New features===
-*the various parameter types now have their scope restricted to the grammar element/s for which they are defined, instead of having them all be equally valid for all grammar elements.
-*added two new flags added to MessageDecorators that instruct the stack to copy the decorator from the INVITE request to any resulting stack generated CANCEL requests or ACK failure requests. This functionality was added so that it is possible to decorate all request messaging on the wire.
-*enhanced the MarkListener class to allow control over the DNS Grey / Black list. The onMark function is now called before insertion to the list and you can now change the expiry value to 0 if you don't want the entry added to the grey/black list, or change the amount of time it is on the list.
-*reduced the memory footprint associated with storing URIs
-*change how branch parameters are encoded.
-**old format: z9hG4bK-d8754z-<branch>-<transportseq>-<clientData>-<sigcompCompartment>-d8754z-
-**new Format: z9hG4bK-524287-<transportseq>-<clientData>-<sigcompComprtment>-<branch>
-***this format encodes faster, parses faster (with _much_ simpler code), and takes up less space on the wire.
-**some other small optimizations; avoid copies associated with calling Data::base64encode()/base64decode() on empty Datas, and reorder the SIP cookie comparisons to be more efficient.
-*reduced the memory consumed by storing TransationState
-*reduction in buffer reallocations while encoding a SipMessage
-*added multiple threads in the stack. Allow transaction processing, transport processing, and DNS processing to be broken off into separate threads.
-**SipStack::run() causes the creation and run of three threads; a TransactionControllerThread, and TransportSelectorThread, and a DnsThread. You continue to use stuff like StackThread and EventStackThread to give cycles to the rest of the stack (mainly processing app timers and statistics logging). In other words, to use the new multi-threaded mode, all you have to do is throw in a call to SipStack::run() before you fire up your normal SipStack processing, and a SipStack::shutdownAndJoinThreads() when you're done.
-**in the Connection read/write code, process reads/writes until EAGAIN, or we run out of stuff to send. Gives a healthy performance boost on connection-based transports.
-**in TransactionController, put transaction timers in their own fifo. This prevents timers from firing late when the state machine fifo gets congested.
-**process at most 16 TransactionMessages from the state machine fifo at a time, to prevent starving other parts of the system.
-**unhook the TransactionController's processing loop from that of the TransportSelector. This simplifies this API considerably, but required the addition of a new feature to Fifo. Fifo can now take an (optional) AsyncProcessHandler* that will be notified when the fifo goes from empty to non-empty. Actually pretty useful.
-**allow setPollGrp() to be called multiple times on the various classes that have this function. This allows the FdPollGrp to be re-set when the SipStack enters multithreaded mode.
-**added a "multithreadedstack" --thread-type option to testStack. Exercise this option in testStackStd.sh
-**added the ability to run any of the existing Transport objects in their own thread, by a combination of a new transport flag (RESIP_TRANSPORT_FLAG_OWNTHREAD), and a new TransportThread class. Added support for this mode to testStack using the --tf option. Also exercised this feature in testStackStd.sh.
-**installed SelectInterruptors at the TransportSelector, each Transport object, and the DnsStub (this last one required moving SelectInterruptor to rutil). This is critical to making multithreaded mode work in a performant manner, and imposes almost no performance penalty due to the way they are invoked.
-**SipStack now creates its own SelectInterruptor if one is not supplied externally. This is because it is critical to be able to wake the TransactionController up when new work comes down from the TU, or from the transports.
-*new congestion-management framework
-**allow testStack, tfm/repro/sanityTests, and repro to be run with a congestion manager via a configuration flag.
-**efficient wait-time estimation in AbstractFifo; keeps track of how rapidly messages are consumed, allowing good estimates of how long a new message will take to be serviced. More efficient than the time-depth logic in TimeLimitFifo, and a better predictor too.
-**the ability to shed load at the transport level when the TransactionController is congested, in a very efficient manner, using new functionality in Helper and SipMessage (Helper::makeRawResponse() and SipMessage::encodeSingleHeader())
-**the ability to shed load coming from the TU when the TransactionController is congested. This is crucial when congestion is being caused by a TU trying to do too much.
-**changed the way load-shedding is handled for TransactionUsers to use the new API
-**a flexible congestion-management API, allowing load-shedding decisions to be made in an arbitrary fashion.
-**a generalized CongestionManager implementation that is powerful enough to be useful.
-**the TransactionController will now defer retransmissions of requests if sufficiently congested (ie; the response is probably stuck in mStateMacFifo)
-*the TransactionController now determines its hostname with a single call to DnsUtil::getLocalHostName() on construction, for use in 503s. Previously, it would make this call every time a 503 was sent; this call blocks sometimes!
-*don't call DnsResult::blacklistLast() on a Retry-After: 0
-*several fixes for the processing loop in testStack that were causing starvation of one type of work or another when congestion occurred.
-*small efficiency improvement in Random::getCryptoRandom(int) Random::getCryptoRandom(unsigned int len) was implemented by calling Random::getCryptoRandom() repeatedly, and collecting the return values in a buffer. In the openssl case, we now use a single call to RAND_bytes().
-*use a priority_queue instead of a multiset for storing timers.
-*slight refactoring of Timer so that transaction timers and payload timers (ie; timers that carry a Message*) are a separate classes. Transaction timers no longer have an unused Message* member, and payload timers no longer have the unused transaction-id, Timer::Type, and duration. This saves a _lot_ of memory for apps that use lots of app timers with long lifetimes.
-*less wasteful population of Call-IDs: When generating Call-IDs, Helper was computing an md5 hash of the hostname and some salt, hex-encoding it, and then Base64 encoding the hex data. We now Base64 encode the md5 hash directly. This is less computationally expensive, requires less memory because the resulting string is half the size, and requires fewer bytes on the wire.
-*make TransactionMap case-insensitive; Data::caseInsensitiveTokenHash() is fast enough that performance actually increases a little.
-*std::bitset-based parsing in a number of places for improved performance
-*don't check whether the encoding tables are initted for every single character; check once before the encode operation begins. Also, checking the value of a static bool to determine whether an init has been carried out is pointless; that bool might not be initted yet, and it could have any value. The static init code now copes with both accesses to the encoding tables during static initialization, and from multiple threads during runtime.
-*don't bother generating a transaction identifier unless the parse fails to extract one.
-*some refactoring of the FdPollGrp stuff. Now is compatible with cares, using a bit of a hack. Also compatible with being driven with the old buildFdSet()/select()/process(FdSet&) call sequence, although this is now deprecated. Fixing these compatibility problems allowed us to switch over to using FdPollGrp in all cases, instead of having dual mode everywhere.
-*buffer classes for Fifo to reduce lock contention. Using them in a few places, will use them in more once we phase out TimeLimitFifo with the new congestion management code.
-*use the --ignore-case option for generation of ParameterHash.cxx, instead of the nasty sed rewriting we are using now. Should also be slightly faster, since gperf handles case-insensitive hashing more efficiently than our hack was.
-*added a local memory pool to SipMessage, to cut down (dramatically) on heap allocation overhead. Some minor refactoring to free up wasted space in SipMessage as well (makes more room for the pool). Changing the way the start-line is stored to no longer use a full-blown ParserContainer+ HeaderFieldValueList.
-*added method to SipStack to be able to retrieve a dump of the DNS cache
-*added operator<< for Statistics Payload
-*allow SipStack statistics to be reset/zero'd out
-*modified GetStackStats command to be able to retrieve statistics that are accurate at the time of the request, instead of just returning the statistics as of the last statistics interval
-*added a new method to SipStack so that you can post to TU without needing to clone/copy the message
-*tls: add support for loading a directory of root certificates or a file containing a bundle of roort certificates
-*tls: support for mutual TLS/client certificate verification
-*tls: optional facility to accept email address subjectAltNames as if they were SIP URIs
-*added new Helper method: Tuple getClientPublicAddress(const SipMessage& request) - look at Via headers, and finds the first public IP address closest to the sending client.
-*renamed Helper::isSenderBehindNAT to isClientBehindNAT for consistency
-*allow a DateCategory to be created from time_t
-*allow transport type be pre-populated in a via header to force the stack to use a particular transport type (ie. UDP, TCP, TLS)
-
-===Bug fixes===
-*fix for testStack running on OS X
-*fixed issue where resiprocate would encode headers that are not directly modified, potentially causing header formatting to change where there is a difference in resip encoding vs received encoding.
-**modified LazyParser to encode from the raw HeaderFieldValue if it has not been modified (or at least, the non-const version of checkParsed() has not been called).
-**added SipMessage::const_header for the various header types, to allow explicit const-only access with a non-const SipMessage
-**use this const_header function in a number of places where we do not want the LazyParser marking itself as "dirty".
-*fixed a bug in URI parsing code when an @ or : appeared in a quoted parameter
-*fix for DtlsTransport - fix in _doHandshake(), switch must be done on SSL_get_error() return value
-*fixed a static initialization race with the Uri encoding tables
-*fix for missing statistics in output string for stack statistics
-*fix possible memory corruption in SdpContents::Session::Medium::codecs() due to Codec::parse() and the Medium's AttributeHelper, the AttributeHelper free's up the memory that was used by parse()
-*fix to make nc (nonce count) lowercase, per definition of LHEX in RFC2831
-*use getaddrinfo() instead of the non-threadsafe gethostbyname().
-*remove unused (and non-threadsafe) Timer::mTimerCount/Timer::mId.
-*get rid of a wasteful double-encode, in Message.cxx
-*fixed a nasty bug in NameAddr - where unknown parameters uri parameters on a NameAddr/Uri with no angle brackets are treated as NameAddr parameters. When this is done, the memory for these parameters was only a temporary Data object.
-*resip TCP transports can crash repro on uncaught exception - if garbage is received on the socket, and there is no Content-Length header, then SipMessage::Exception can throw, and it was not caught with the existing ParseException catch handler. Changed to catch BaseException instead.
-*fixed possible assert if a transport error is seen after trying to send an ACK message
-*added TlsDestructorInitializer as a field to LogStaticInitializer in order to make sure an instance of TlsDestructorInitializer is created before LogStaticInitializer is initialized
-*removed print in TcpConnection that could end up printing garbage at the end of messages that are not null terminated
-*added loopback address checking to Tuple::isPrivateAddress
-*fixed a bad value passed to the macro RESIP_HeapCount in KeepAlivePong.h
-
-
-==DUM==
-===New features===
-*added a getRequest() method to ClientOutOfDialogReq so that the request for the response can be accessed
-*implemented InviteSession::reject while in the SentReinviteAnswered state. This is useful when needing to reject with an empty ACK an offer that was requested (using an empty INVITE) while in a dialog.
-*added ability to asynchronously end an AppDialogSet using AppDialogSet::endCommand.
-*added new public APIs to DialogUsageManager so that the application can find AppDialogs/AppDialogSets from a DialogId or a DialogSetId. This is useful if the application wants to find a dialog set from a SIP message alone.
-*added the ability to end a publication without sending a final PUBLISH with an expires of 0
-*modified client subscription to allow a subscription to be terminated without sending a final SUBSCRIBE request, useful in cases where an extension Subscription-State is used that signifies that the subscription is terminated
-*added ServerAuthManager support for UA's who set auth username="user@domain" rather than username="user"
-*support for mutual TLS/client certificate verification (as DUM feature)
-*enhanced ServerRegistration:
-**ensure that ContactInstanceRecord::mReceivedFrom is always populated - not just in outbound use cases - added a new flag to indicate when flow routing is required
-**added a new mPublicAddress flag member to ContactInstanceRecord - to assist repro feature to do geo proximity routing
-*test/basicClient - allow subscription and call if not registering
-
-===Bug fixes===
-*fixed a bug where we were using a description parameter in a Reason header, instead of a text parameter
-*fixed incorrect assert in ServerSubscription due to missing break statement
-*removed unsafe logging statement in DumTimeout - if DUM and stack are in different threads, then crash could occur
-*fixed a bug where the CSeq can be wrong in a client subscription re-subscribe / refresh in the case where we receive the first NOTIFY before the 200/SUB response
-*dum/test/basicClient - fixed a trap during shutdown, due to order of destructed objects
-*fixed a bug when using the registration sync mechanism - the ServerRegistration onRefresh callback could be incorrectly generated instead of the onAdd callback when a registration is added, due to the record lingering in memory
-
-
-==repro==
-===New features===
-*added new configuration mechanism for repro
-**removed use of popt, now using a new name/value pair approach (using new rutil/ConfigParser classs) to read settings from a .config file
-**allows command line options - but is not backwards compatible with old popt command line format
-*added a new Command interface/server to repro that operates over a TCP socket and uses XML formatted messaging. Supporting the following commands:
-**GetStackInfo
-**GetStackStats
-**ResetStackStats
-**LogDnsCache
-**ClearDnsCache
-**GetDnsCache
-**GetCongestionStats
-**SetCongestionTolerance
-**Shutdown
-**Restart
-**GetProxyConfig
-*added new reprocmd executable that connects to repro via new command socket server and sends commands based on command line arguments
-*upgraded the MySQL support in repro to a deployable state
-**allow MySQL connection parameters to be specified in repro config
-**cleaned up MySQL initialization, so we fail to start if there is a db connect error
-**remove all generic throws from MySQL implementation
-**implemented MySQL connection recovery on errors - when connection errors occur on query, try to re-connect immediately (once)
-**optimized query building in MySQLDb class
-**added ability for repro.config to provide a select statement that allows a1 password retrieval from an arbitrary database table on the MySQL server
-**added .sql script to create repro tables on MySQL
-**added a singleResultQuery API to MySqlDb
-**added my sql implementation of AVPs (attribute-value-pair) with two indexes/attributes
-**increase MySQL AVP (attribute-value-pair) table size for value field from 1024 to 4096
-**modifications to make MySQL client use properly protected for multi-threaded access - refuse to start if linked with mysql library that doesn't support multi-threading
-**use CLIENT_MULTI_RESULTS flag when opening mysql database (enables multiple results, since some custom stored procedures might require this)
-*add ability for a repro admin to add manual / permanent registrations (including Path information) - such manually added registrations are persisted to the database, and loaded at startup - manual registrations can be added on the Registration Web Page
-*added new Baboon: GeoProximityTargetSorter - If enabled, then this baboon can post-process the target list. This includes targets from the StaticRoute monkey and/or targets from the LocationServer monkey. Requests that meet the filter criteria will have their Target list, flatened (serialized) and ordered based on the proximity of the target to the client sending the request. Proximity is determined by looking for a x-repro-geolocation="<latitude>,<longitude>" parameter on the Contact header of a received request, or the Contact headers of Registration requests. If this parameter is not found, then this processor will attempt to determine the public IP address closest to the client or target and use the MaxMind Geo IP library to lookup the geo location.
-*added new RequestFilter monkey
-**allows user to configure conditions under which an inbound request should be rejected or not
-**allows two regular expression conditions that can be applied to any SIP message header: this includes the request-line, standard SIP headers and custom SIP headers. If a header that can appear multiple time is specified, then each instance of the header is checked.
-**When conditions are met, allows the action carried out to be defined:
-***Accept - accepts this request and stops further processing in Request Filter monkey
-***Reject - rejects this request with the provided SIP status code and reason text
-***SQL query - only available when MySQL support is compiled in - runs an arbitrary stored procedure or query, using replacement strings from the 2 condition regular expressions
-****query must return an empty string or "0" to instruct repro to Accept the request, or a string containing "<SIP Reject Status Code>[, <SIP Reject Reason>]" to Reject the request
-****using the repro configuration file the SQL Query can be configured to operate on a completely different mySQL instance/server than the repro configuration
-**filters are defined in the HTTP web interface via new Add Filter, Edit Filter and Show Filters web pages. There is an ability to test the condition regular expressions from the web page as well.
-**other Monkey settings are configured in the repro configuration file or via command line: DisableRequestFilterProcessor, RequestFilterDefaultNoMatchBehavior, RequestFilterDefaultDBErrorBehavior, RequestFilterMySQLServer (and other mySQL related settings)
-**can be used to implement a User Blocking functionality - ie. calls and instant messages from user X to user Y should always be blocked, because user X is in user Y's block list
-**introduced new FilterStore configuration database table to store the Filters configured on the web pages
-*added optional MessageSilo support to repro
-**stores IM's (ie. SIP MESSAGE requests) for offline users
-**replays messages to users when they register (ie. come back online)
-**records are persisted to a database table, so they survive shutdowns
-**configurable filters exist for DestUri, MimeType, MessageBody size
-*Web Admin GUI improvements
-**made use of HTML tables consistent across all web interfaces pages
-**made table backgrounds white to improved appearance
-**added title to right hand side pane
-**cleaned up formatting on many pages
-**added warning to Domains page, that repro must be restarted
-**added bottom banner with link to www.resiprocate.org
-**added repro version display on top banner
-**added new Settings page to repro web interface to show current command line / files settings in use - will also display some some low level stack info, congestion stats (if enabled), and the contents of the DNS cache
-**added Clear DNS Cache button to settings page
-**added Restart Proxy button to settings page (reloads everything, applies new configuration, but keeps in memory registration table)
-**added display of registered contact's QValue on registrations web page
-**Routes: stop webpage from being able to add two routes with the same Key, optimized data fetch for displaying routes on web page
-**propagate db insert/update failures to callers - web interface now shows errors if record fails to update in db
-*added an ability to configure a different database instance for some of the repro database tables. New configuration file settings, RuntimeMySQLServer and it's subsettings, were added to facilitate this. The Users and MessageSilo database tables are different from the other repro configuration database tables, in that they are accessed at runtime as SIP requests arrive. It may be desirable to use BerkeleyDb for the other repro tables (which are read at starup time, then cached in memory), and MySQL for the runtime accessed tables; or two separate MySQL instances for these different table sets. The new configuration settings allow you to achieve this.
-*added option to enable some basic P-Asserted-Identity header handling
-**After auth is successful
-***if P-Perferred-Identity header is present remove it
-***if no P-Asserted-Identity header is present, then add one
-**Removal of P-Asserted-Identity if Privacy header is set to "id"
-***Note: Since we have no better mechanism to determine if destination is trusted or not we assume that all destinations outside our domain are not-trusted and will remove the P-Asserted-Identity header
-*added ability for repro to report a 404 error when attempting to reach a user that does not exist - previously repro would always send a 480 response when attempting to reach an AOR that wasn't registered
-*major changes to how repro is started up, to allow easier additions of custom startup logic, such as adding custom Processors (Monkeys, Lemurs and Baboons) to the default Processor chains
-**almost all logic that was in repro.cxx has been moved out to a new class (ReproRunner), and split into smaller virtual methods that can be overridden
-**see comments at the top of repro.cxx for an example of how to add custom processors
-*add support for daemonizing on platforms supporting fork()
-*added ability to create a UNIX PID file on startup
-*add support for loading a directory of root certificates or a file containing a bundle of root certificates
-*support for mutual TLS/client certificate verification (as repro monkey)
-*tls: config option to accept email address subjectAltNames as if they were SIP URIs
-*added congestion manager settings to be configured in repro configuration file
-*added KeyValueStore to three strategic locations in repro, allowing custom Processors (Monkeys, Lemurs and Baboons) to store state scoped as follows:
-**Global Proxy Scope - Proxy::getKeyValueStore
-**Request Scope - RequestContext::getKeyValueStore
-**Target Scope - Target::getKeyValueStore
-**Before this storage can be used you must statically allocate a storage key. See mFromTrustedNodeKey use in the IsTrustedNode class for an example.
-*implemented proper q-value processing of contacts in a redirect response
-*modified repro so that Registration authentication uses the same pool of worker threads that the DigestAuthenticator uses when looking up credentials from the database. Previously only auth look ups for non-REGISTER requests (ie. INVITE, SUBSCRIBE, etc.) would be done in a manner that didn't block inbound message processing. A lengthy auth check for a REGISTER request would cause delays in processing all other REGISTER requests.
-*allow custom repro implementations to add themselves to the RegistrarHandler so that registration messages can be processed and reacted to
-*added abililty to tweak timer T1 in repro configuration
-*allow specifying a ;lr flag on static routes to perform loose routing, instead of re-writing the request URI
-*modified repro to allow an application overridden RequestContext to be able to provide a virtual fn for cancelClientTransaction
-*added resip ExternalLogger to repro, so that Error logs are also logged to the console when file logging is enabled
-*added some new configuration settings: LogFileName, LogFileMaxBytes
-*made the number of worker threads in the repro authgrabber dispatcher configurable via the repro configuration file
-*modified UserAuthGrabber to use UserStore::getUserAuthInfo, instead of UserStore::getUserInfo API - we don't use the other fields retrieved, so this will provide an optimization
-*optimized the Worker thread to avoid making a copy of the Message when posting to the stack
-*added new config setting StatisticsLogInterval to specify how often statistics are dumped to the log files
-*added two new constructors to QValueTarget to make is easier to form targets from a NameAddr or Uri only
-*renamed Target::targetPtrCompare to Target::priorityMetricCompare to be more descriptive
-*cleanup some old hacks now that we have the ability to manually add registrations
-**ParallelForkStaticRoutes no longer combines StaticRoutes Targets and LocationServer Targets
-**static Routes are no longer added as QValueTargets, they are now added as simple Targets. So they are no longer susceptible to the various QValue Settings - ie. QValueMsBeforeCancel.
-**added new ContinueProcessingAfterRoutesFound setting: By default (false) we will stop looking for more Targets if we have found matching routes. Setting this value to true will allow the LocationServer Monkey to run after StaticRoutes have been found. In this case the matching StaticRoutes become fallback targets, processed only after all location server Targets fail.
-*cleaned up Processor and ProcessorChain classes
-**added mName property in anticipation of a future capability to define processor chains in the configuration file
-**simplified operator<< for processors, to use Name
-*added a series of interfaces to make is easier to implement new Asynchronous Monkey's / Processors that utilize a common thread pool
-*removed getTransactionId from ForkControlMessage - method exists on base class, so it's not needed
-*removed getTransactionId and tid() from UserInfoMessage - getTransactionId method exists on base class, so they are not needed
-*added AsyncProcessorDispatcher / thread pool to repro that be shared by all AsyncProcessors - currently used by new RequestFilter and Message Silo monkeys
-*cleaned up some implementation in AbstractDb to remove some code duplication
-*remove unused AbstractDb API's: writeRoute and writeFilter
-*added ability for tables to have non-unique keys (ie. duplicate records)
-*added secondary database support to BerkeleyDb - allows tables with a secondary index
-*optimized data copies when reading records from BerkeleyDb
-*modified WorkerThread to support work that does not require a response to be queued back to the stack
-*added database transaction support to BerekelyDb and MySQL implementations
-*removed unused SipStack parameter to DigestAuthenticator monkey
-*option to enforce the requirement of a client certificate for third party domains
-*added new repro setting to assume that first hop supports outbound
-*support for storing passwordHashAlt - changes users schema and users db version. passwordHashAlt can be used with MySQLCustomUserAuthQuery, in future it will work seamlessly in conjunction with passwordHash
-*avoid unnecessary iteration through target list in StaticRoute when try to determine if auth is required
-*removed some unused code in ResponseContext: addOutboundBatch and mOutboundMap
-
-===Bug fixes===
-*fix for a long standing issue in repro that started in rev6794, where repro can be over protective and issue 403 responses for legitimate mid-dialog requests. The issue occurs when a repro domain user forms a dialog with a user in another external domain. Any mid-dialog requests coming from the external domain would get 403'd. This was due to the logic in the AmIResponsible monkey, and the fact that such requests have the repro endpoints contact address in the RequestUri (typically the endpoints IP address), so not belonging to repro's domain, and the From user is not being from repro's domain.
-*fix a bug in repro web interface, where fragmented HTTP messages were not being handled correctly
-
-
-==reTurn==
-===New features===
-*reTurnServer: read config settings from reTurnServer.config instead of using hard coded values
-*add support for daemonizing on platforms supporting fork()
-*log error in UdpServer if failure to bind
-*add StackLog logging of request type when encoding a message
-*added a man page for reTurnServer
-*added ability to create a UNIX PID file on startup
-*return server - suppress socket errors when closing relay
-
-===Bug fixes===
-*fixed problem where classic stun responses come from the wrong socket
-*ensure asio doesn't throw exceptions under error conditions
-*added missing request type TurnCreatePermissionMethod to operator<<
-*log hex() version of HMAC keys, since they are binary
-*client API: TurnSocket - ensure we are connected before allowing send
-*client API: Remove warning about 'this' use in initiator list - pointer is only stored
-*client API: Increase allowed send size from 1024 bytes to 2048
-*client API: fix potential memory leak with mActiveRequestMap (TurnAsyncSocket class)
-*client API: ensure retrans timer is stopped when request is removed from map
-
-
-==tfm (repro)==
-===New features===
-*added VS2008 project files for Windows
-*move tfm/contrib items to top level contrib directory
-*make file logging the default on tfm, since console logging blocks the run too much
-
-===Bug fixes===
-*adjust some timeout values so that tests will pass on slower systems
-
-
-==tfm (dum)==
-===Bug fixes===
-*fixed a place where a NameAddr param (methods) was being used as a Uri param
-
-
-==apps/sipdial==
-===New features===
-*add support for TLS and sips uri scheme
Index: reSIProcate_8_0.sln
===================================================================
--- reSIProcate_8_0.sln (.../branches/resiprocate-1.8) (revision 9855)
+++ reSIProcate_8_0.sln (.../main) (revision 9855)
@@ -108,6 +108,12 @@
Release.AspNetCompiler.Debug = "False"
EndProjectSection
EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "repro", "repro", "{89D1D684-90BC-49A2-8184-943535F66CD5}"
+ ProjectSection(WebsiteProperties) = preProject
+ Debug.AspNetCompiler.Debug = "True"
+ Release.AspNetCompiler.Debug = "False"
+ EndProjectSection
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Win32 = Debug|Win32
@@ -224,4 +230,9 @@
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
+ GlobalSection(NestedProjects) = preSolution
+ {9D8D2649-213F-49D3-A8B0-C1849C611654} = {89D1D684-90BC-49A2-8184-943535F66CD5}
+ {31B0654F-E08E-405F-909F-80F86CB14B9E} = {89D1D684-90BC-49A2-8184-943535F66CD5}
+ {02954DA6-5079-4717-BC3D-B3ACA815CFED} = {89D1D684-90BC-49A2-8184-943535F66CD5}
+ EndGlobalSection
EndGlobal
Index: resip/dum/RegistrationHandler.hxx
===================================================================
--- resip/dum/RegistrationHandler.hxx (.../branches/resiprocate-1.8) (revision 9855)
+++ resip/dum/RegistrationHandler.hxx (.../main) (revision 9855)
@@ -17,7 +17,7 @@
public:
virtual ~ClientRegistrationHandler() { }
/// Called when registraion succeeds or each time it is sucessfully
- /// refreshed.
+ /// refreshed (manual refreshes only).
virtual void onSuccess(ClientRegistrationHandle, const SipMessage& response)=0;
// Called when all of my bindings have been removed
Index: resip/stack/Token.cxx
===================================================================
--- resip/stack/Token.cxx (.../branches/resiprocate-1.8) (revision 9855)
+++ resip/stack/Token.cxx (.../main) (revision 9855)
@@ -181,6 +181,7 @@
}
defineParam(text, "text", ExistsOrDataParameter, "RFC 3840");
+defineParam(cause, "cause", UInt32Parameter, "RFC 3326");
defineParam(dAlg, "d-alg", DataParameter, "RFC 3329");
defineParam(dQop, "d-qop", DataParameter, "RFC 3329");
defineParam(dVer, "d-ver", QuotedDataParameter, "RFC 3329");
Index: resip/stack/ParameterHash.gperf
===================================================================
--- resip/stack/ParameterHash.gperf (.../branches/resiprocate-1.8) (revision 9855)
+++ resip/stack/ParameterHash.gperf (.../main) (revision 9855)
@@ -22,6 +22,7 @@
isfocus, ParameterTypes::isFocus
actor, ParameterTypes::actor
text, ParameterTypes::text
+cause, ParameterTypes::cause
extensions, ParameterTypes::extensions
+sip.instance, ParameterTypes::Instance
reg-id, ParameterTypes::regid
Index: resip/stack/ParameterTypes.hxx
===================================================================
--- resip/stack/ParameterTypes.hxx (.../branches/resiprocate-1.8) (revision 9855)
+++ resip/stack/ParameterTypes.hxx (.../main) (revision 9855)
@@ -102,6 +102,7 @@
defineParam(isFocus, "isfocus", ExistsParameter, NameAddr, "RFC 3840");
defineParam(actor, "actor", QuotedDataParameter, NameAddr, "RFC 3840"); // principal|msg-taker|attendant|information
defineParam2(text, "text", ExistsOrDataParameter, NameAddr, Token, "RFC 3326/3840");
+defineParam(cause, "cause", UInt32Parameter, Token, "RFC3326");
defineParam(extensions, "extensions", QuotedDataParameter, NameAddr, "RFC 3840"); //list
defineParam(Instance, "+sip.instance", QuotedDataParameter, NameAddr, "RFC 5626"); // <> quoted
defineParam(regid, "reg-id", UInt32Parameter, NameAddr, "RFC 5626");
Index: resip/stack/ParameterTypeEnums.hxx
===================================================================
--- resip/stack/ParameterTypeEnums.hxx (.../branches/resiprocate-1.8) (revision 9855)
+++ resip/stack/ParameterTypeEnums.hxx (.../main) (revision 9855)
@@ -61,7 +61,8 @@
defineParam(type, "type", QuotedDataParameter, "RFC 3840"), // list
defineParam(isFocus, "isfocus", ExistsParameter, "RFC 3840"),
defineParam(actor, "actor", QuotedDataParameter, "RFC 3840"), // principal|msg-taker|attendant|information
- defineParam(text, "text", ExistsOrDataParameter, "RFC 3840"), // using ExistsOrDataParameter so this parameter is compatible with both RFC3840 and RFC3326
+ defineParam(text, "text", ExistsOrDataParameter, "RFC 3326/3840"), // using ExistsOrDataParameter so this parameter is compatible with both RFC3840 and RFC3326
+ defineParam(cause, "cause", UInt32Parameter, "RFC3326"),
defineParam(extensions, "extensions", QuotedDataParameter, "RFC 3840"), //list
defineParam(Instance, "+sip.instance", QuotedDataParameter, "RFC 5626"), // <> quoted
Index: resip/stack/TransportSelector.cxx
===================================================================
--- resip/stack/TransportSelector.cxx (.../branches/resiprocate-1.8) (revision 9855)
+++ resip/stack/TransportSelector.cxx (.../main) (revision 9855)
@@ -620,9 +620,9 @@
GenericIPAddress addr = WinCompat::determineSourceInterface(target.toGenericIPAddress());
source.setSockaddr(addr);
}
- catch (WinCompat::Exception&)
+ catch (WinCompat::Exception& ex)
{
- ErrLog (<< "Can't find source interface to use");
+ ErrLog (<< "Can't find source interface to use: " << ex);
throw Transport::Exception("Can't find source interface", __FILE__, __LINE__);
}
#else
Index: resip/stack/gperf_w32.bat
===================================================================
--- resip/stack/gperf_w32.bat (.../branches/resiprocate-1.8) (revision 9855)
+++ resip/stack/gperf_w32.bat (.../main) (revision 9855)
@@ -1,17 +1,14 @@
@echo off
echo WARNING - use of this batch file is only recommended for advanced users.
echo It is used to automate the first step required in creating the
-echo GPERF HASH files for resiprocate on windows. Once this step
-echo has completed the generated files must be manually edited
-echo (at least until proper win 32 scripts are created)
-echo for case insensitvity.
+echo GPERF HASH files for resiprocate on windows.
echo.
echo Note - Ensure gperf.exe is present in the path or resip/stack directory
echo before continuing
echo.
pause
-gperf -D -E -L C++ -t -k "*" --compare-strncmp -Z MethodHash MethodHash.gperf > MethodHash.cxx
-gperf -D -E -L C++ -t -k "*" --compare-strncmp -Z HeaderHash HeaderHash.gperf > HeaderHash.cxx
-gperf -D -E -L C++ -t -k "*" --compare-strncmp -Z ParameterHash ParameterHash.gperf > ParameterHash.cxx
-echo Don't forget to manually add the tolower calls - see gperfNotes.txt and Makefile
+gperf -C -D -E -L C++ -t -k "*" --compare-strncmp -Z MethodHash MethodHash.gperf > MethodHash.cxx
+gperf -C -D -E -L C++ -t -k "*" --compare-strncmp --ignore-case -Z HeaderHash HeaderHash.gperf > HeaderHash.cxx
+gperf -C -D -E -L C++ -t -k "*" --compare-strncmp --ignore-case -Z ParameterHash ParameterHash.gperf > ParameterHash.cxx
+echo MethodHash.cxx, HeaderHash.cxx and ParameterHash.cxx have been created using gperf.
pause
Index: resip/stack/ParameterTypes.cxx
===================================================================
--- resip/stack/ParameterTypes.cxx (.../branches/resiprocate-1.8) (revision 9855)
+++ resip/stack/ParameterTypes.cxx (.../main) (revision 9855)
@@ -65,6 +65,7 @@
defineParam(isFocus, "isfocus", ExistsParameter, NameAddr, "RFC 3840");
defineParam(actor, "actor", QuotedDataParameter, NameAddr, "RFC 3840"); // principal|msg-taker|attendant|information
defineParam2(text, "text", ExistsOrDataParameter, NameAddr, Token, "RFC 3326/3840");
+defineParam(cause, "cause", UInt32Parameter, Token, "RFC3326");
defineParam(extensions, "extensions", QuotedDataParameter, NameAddr, "RFC 3840"); //list
defineParam(Instance, "+sip.instance", QuotedDataParameter, NameAddr, "RFC 5626"); // <> quoted
defineParam(regid, "reg-id", UInt32Parameter, NameAddr, "RFC 5626");
Index: resip/stack/ParameterHash.cxx
===================================================================
--- resip/stack/ParameterHash.cxx (.../branches/resiprocate-1.8) (revision 9855)
+++ resip/stack/ParameterHash.cxx (.../main) (revision 9855)
@@ -176,7 +176,7 @@
{
enum
{
- TOTAL_KEYWORDS = 89,
+ TOTAL_KEYWORDS = 90,
MIN_WORD_LENGTH = 1,
MAX_WORD_LENGTH = 13,
MIN_HASH_VALUE = 2,
@@ -185,183 +185,185 @@
static const struct params wordlist[] =
{
-#line 39 "ParameterHash.gperf"
+#line 40 "ParameterHash.gperf"
{"lr", ParameterTypes::lr},
-#line 37 "ParameterHash.gperf"
+#line 38 "ParameterHash.gperf"
{"ttl", ParameterTypes::ttl},
-#line 63 "ParameterHash.gperf"
+#line 64 "ParameterHash.gperf"
{"stale", ParameterTypes::stale},
-#line 59 "ParameterHash.gperf"
+#line 60 "ParameterHash.gperf"
{"nc", ParameterTypes::nc},
#line 23 "ParameterHash.gperf"
{"actor", ParameterTypes::actor},
-#line 82 "ParameterHash.gperf"
+#line 83 "ParameterHash.gperf"
{"site", ParameterTypes::site},
-#line 53 "ParameterHash.gperf"
+#line 54 "ParameterHash.gperf"
{"rport", ParameterTypes::rport},
-#line 70 "ParameterHash.gperf"
+#line 71 "ParameterHash.gperf"
{"reason", ParameterTypes::reason},
#line 10 "ParameterHash.gperf"
{"data", ParameterTypes::data},
-#line 58 "ParameterHash.gperf"
+#line 59 "ParameterHash.gperf"
{"nonce", ParameterTypes::nonce},
-#line 55 "ParameterHash.gperf"
+#line 56 "ParameterHash.gperf"
{"cnonce", ParameterTypes::cnonce},
#line 11 "ParameterHash.gperf"
{"control", ParameterTypes::control},
-#line 62 "ParameterHash.gperf"
+#line 63 "ParameterHash.gperf"
{"response", ParameterTypes::response},
-#line 33 "ParameterHash.gperf"
+#line 34 "ParameterHash.gperf"
{"transport", ParameterTypes::transport},
-#line 57 "ParameterHash.gperf"
+#line 58 "ParameterHash.gperf"
{"id", ParameterTypes::id},
-#line 76 "ParameterHash.gperf"
+#line 77 "ParameterHash.gperf"
{"protocol", ParameterTypes::protocol},
-#line 51 "ParameterHash.gperf"
+#line 52 "ParameterHash.gperf"
{"rinstance", ParameterTypes::rinstance},
-#line 61 "ParameterHash.gperf"
+#line 62 "ParameterHash.gperf"
{"realm", ParameterTypes::realm},
-#line 28 "ParameterHash.gperf"
+#line 29 "ParameterHash.gperf"
{"ob", ParameterTypes::ob},
-#line 32 "ParameterHash.gperf"
+#line 33 "ParameterHash.gperf"
{"name", ParameterTypes::name},
-#line 29 "ParameterHash.gperf"
+#line 30 "ParameterHash.gperf"
{"gr", ParameterTypes::gr},
-#line 47 "ParameterHash.gperf"
+#line 48 "ParameterHash.gperf"
{"tag", ParameterTypes::tag},
-#line 52 "ParameterHash.gperf"
+#line 53 "ParameterHash.gperf"
{"comp", ParameterTypes::comp},
-#line 96 "ParameterHash.gperf"
+#line 97 "ParameterHash.gperf"
{"url", ParameterTypes::url},
-#line 34 "ParameterHash.gperf"
+#line 35 "ParameterHash.gperf"
{"user", ParameterTypes::user},
-#line 40 "ParameterHash.gperf"
+#line 25 "ParameterHash.gperf"
+ {"cause", ParameterTypes::cause},
+#line 41 "ParameterHash.gperf"
{"q", ParameterTypes::q},
-#line 26 "ParameterHash.gperf"
+#line 27 "ParameterHash.gperf"
{"+sip.instance", ParameterTypes::Instance},
-#line 84 "ParameterHash.gperf"
+#line 85 "ParameterHash.gperf"
{"mode", ParameterTypes::mode},
-#line 90 "ParameterHash.gperf"
+#line 91 "ParameterHash.gperf"
{"model", ParameterTypes::model},
#line 18 "ParameterHash.gperf"
{"application", ParameterTypes::application},
-#line 68 "ParameterHash.gperf"
+#line 69 "ParameterHash.gperf"
{"uri", ParameterTypes::uri},
-#line 80 "ParameterHash.gperf"
+#line 81 "ParameterHash.gperf"
{"size", ParameterTypes::size},
-#line 98 "ParameterHash.gperf"
+#line 99 "ParameterHash.gperf"
{"addtransport", ParameterTypes::addTransport},
-#line 67 "ParameterHash.gperf"
+#line 68 "ParameterHash.gperf"
{"qop", ParameterTypes::qop},
-#line 38 "ParameterHash.gperf"
+#line 39 "ParameterHash.gperf"
{"maddr", ParameterTypes::maddr},
#line 13 "ParameterHash.gperf"
{"description", ParameterTypes::description},
-#line 41 "ParameterHash.gperf"
+#line 42 "ParameterHash.gperf"
{"purpose", ParameterTypes::purpose},
-#line 75 "ParameterHash.gperf"
+#line 76 "ParameterHash.gperf"
{"filename", ParameterTypes::filename},
-#line 56 "ParameterHash.gperf"
+#line 57 "ParameterHash.gperf"
{"domain", ParameterTypes::domain},
-#line 35 "ParameterHash.gperf"
+#line 36 "ParameterHash.gperf"
{"ext", ParameterTypes::extension},
#line 24 "ParameterHash.gperf"
{"text", ParameterTypes::text},
-#line 81 "ParameterHash.gperf"
+#line 82 "ParameterHash.gperf"
{"permission", ParameterTypes::permission},
#line 21 "ParameterHash.gperf"
{"type", ParameterTypes::type},
-#line 77 "ParameterHash.gperf"
+#line 78 "ParameterHash.gperf"
{"micalg", ParameterTypes::micalg},
#line 22 "ParameterHash.gperf"
{"isfocus", ParameterTypes::isFocus},
-#line 64 "ParameterHash.gperf"
+#line 65 "ParameterHash.gperf"
{"username", ParameterTypes::username},
-#line 94 "ParameterHash.gperf"
+#line 95 "ParameterHash.gperf"
{"app-id", ParameterTypes::appId},
-#line 86 "ParameterHash.gperf"
+#line 87 "ParameterHash.gperf"
{"charset", ParameterTypes::charset},
-#line 44 "ParameterHash.gperf"
+#line 45 "ParameterHash.gperf"
{"duration", ParameterTypes::duration},
-#line 42 "ParameterHash.gperf"
+#line 43 "ParameterHash.gperf"
{"to-tag", ParameterTypes::toTag},
-#line 45 "ParameterHash.gperf"
+#line 46 "ParameterHash.gperf"
{"expires", ParameterTypes::expires},
-#line 85 "ParameterHash.gperf"
+#line 86 "ParameterHash.gperf"
{"server", ParameterTypes::server},
-#line 71 "ParameterHash.gperf"
+#line 72 "ParameterHash.gperf"
{"d-alg", ParameterTypes::dAlg},
#line 14 "ParameterHash.gperf"
{"events", ParameterTypes::events},
-#line 93 "ParameterHash.gperf"
+#line 94 "ParameterHash.gperf"
{"document", ParameterTypes::document},
-#line 66 "ParameterHash.gperf"
+#line 67 "ParameterHash.gperf"
{"refresher", ParameterTypes::refresher},
-#line 25 "ParameterHash.gperf"
+#line 26 "ParameterHash.gperf"
{"extensions", ParameterTypes::extensions},
-#line 60 "ParameterHash.gperf"
+#line 61 "ParameterHash.gperf"
{"opaque", ParameterTypes::opaque},
-#line 50 "ParameterHash.gperf"
+#line 51 "ParameterHash.gperf"
{"require", ParameterTypes::require},
#line 15 "ParameterHash.gperf"
{"priority", ParameterTypes::priority},
-#line 83 "ParameterHash.gperf"
+#line 84 "ParameterHash.gperf"
{"directory", ParameterTypes::directory},
-#line 27 "ParameterHash.gperf"
+#line 28 "ParameterHash.gperf"
{"reg-id", ParameterTypes::regid},
#line 17 "ParameterHash.gperf"
{"schemes", ParameterTypes::schemes},
-#line 79 "ParameterHash.gperf"
+#line 80 "ParameterHash.gperf"
{"expiration", ParameterTypes::expiration},
-#line 48 "ParameterHash.gperf"
+#line 49 "ParameterHash.gperf"
{"branch", ParameterTypes::branch},
-#line 91 "ParameterHash.gperf"
+#line 92 "ParameterHash.gperf"
{"version", ParameterTypes::version},
-#line 72 "ParameterHash.gperf"
+#line 73 "ParameterHash.gperf"
{"d-qop", ParameterTypes::dQop},
-#line 89 "ParameterHash.gperf"
+#line 90 "ParameterHash.gperf"
{"vendor", ParameterTypes::vendor},
-#line 95 "ParameterHash.gperf"
+#line 96 "ParameterHash.gperf"
{"network-user", ParameterTypes::networkUser},
-#line 49 "ParameterHash.gperf"
+#line 50 "ParameterHash.gperf"
{"received", ParameterTypes::received},
#line 19 "ParameterHash.gperf"
{"video", ParameterTypes::video},
-#line 87 "ParameterHash.gperf"
+#line 88 "ParameterHash.gperf"
{"access-type", ParameterTypes::accessType},
#line 20 "ParameterHash.gperf"
{"language", ParameterTypes::language},
-#line 36 "ParameterHash.gperf"
+#line 37 "ParameterHash.gperf"
{"method", ParameterTypes::method},
#line 16 "ParameterHash.gperf"
{"methods", ParameterTypes::methods},
-#line 43 "ParameterHash.gperf"
+#line 44 "ParameterHash.gperf"
{"from-tag", ParameterTypes::fromTag},
-#line 69 "ParameterHash.gperf"
+#line 70 "ParameterHash.gperf"
{"retry-after", ParameterTypes::retryAfter},
-#line 73 "ParameterHash.gperf"
+#line 74 "ParameterHash.gperf"
{"d-ver", ParameterTypes::dVer},
#line 12 "ParameterHash.gperf"
{"mobility", ParameterTypes::mobility},
-#line 46 "ParameterHash.gperf"
+#line 47 "ParameterHash.gperf"
{"handling", ParameterTypes::handling},
-#line 97 "ParameterHash.gperf"
+#line 98 "ParameterHash.gperf"
{"sigcomp-id", ParameterTypes::sigcompId},
-#line 88 "ParameterHash.gperf"
+#line 89 "ParameterHash.gperf"
{"profile-type", ParameterTypes::profileType},
-#line 54 "ParameterHash.gperf"
+#line 55 "ParameterHash.gperf"
{"algorithm", ParameterTypes::algorithm},
-#line 78 "ParameterHash.gperf"
+#line 79 "ParameterHash.gperf"
{"boundary", ParameterTypes::boundary},
-#line 74 "ParameterHash.gperf"
+#line 75 "ParameterHash.gperf"
{"smime-type", ParameterTypes::smimeType},
-#line 65 "ParameterHash.gperf"
+#line 66 "ParameterHash.gperf"
{"early-only", ParameterTypes::earlyOnly},
+#line 32 "ParameterHash.gperf"
+ {"temp-gruu", ParameterTypes::tempGruu},
#line 31 "ParameterHash.gperf"
- {"temp-gruu", ParameterTypes::tempGruu},
-#line 30 "ParameterHash.gperf"
{"pub-gruu", ParameterTypes::pubGruu},
-#line 92 "ParameterHash.gperf"
+#line 93 "ParameterHash.gperf"
{"effective-by", ParameterTypes::effectiveBy}
};
@@ -370,23 +372,23 @@
-1, -1, 0, 1, -1, 2, -1, 3, -1, -1, 4, -1, -1, -1,
5, 6, 7, -1, -1, 8, 9, 10, 11, 12, 13, -1, -1, 14,
15, 16, 17, -1, 18, -1, 19, -1, -1, 20, 21, 22, -1, -1,
- -1, 23, 24, -1, 25, -1, 26, 27, 28, 29, -1, 30, 31, -1,
- -1, 32, 33, -1, 34, 35, 36, 37, -1, -1, 38, -1, 39, 40,
- 41, -1, -1, -1, 42, -1, 43, 44, 45, -1, -1, 46, 47, 48,
- -1, -1, 49, 50, -1, -1, -1, 51, -1, -1, -1, 52, 53, -1,
- 54, 55, 56, 57, 58, 59, 60, -1, 61, 62, -1, -1, 63, 64,
- 65, -1, -1, 66, 67, 68, 69, -1, 70, 71, -1, 72, -1, -1,
- 73, 74, 75, -1, -1, 76, -1, -1, -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, 77, -1, -1, 78, -1, -1, -1, -1, 79,
- -1, 80, -1, 81, -1, 82, -1, -1, -1, 83, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 84, -1,
- -1, -1, -1, -1, -1, -1, -1, -1, 85, -1, -1, -1, 86, -1,
+ -1, 23, 24, 25, 26, -1, 27, 28, 29, 30, -1, 31, 32, -1,
+ -1, 33, 34, -1, 35, 36, 37, 38, -1, -1, 39, -1, 40, 41,
+ 42, -1, -1, -1, 43, -1, 44, 45, 46, -1, -1, 47, 48, 49,
+ -1, -1, 50, 51, -1, -1, -1, 52, -1, -1, -1, 53, 54, -1,
+ 55, 56, 57, 58, 59, 60, 61, -1, 62, 63, -1, -1, 64, 65,
+ 66, -1, -1, 67, 68, 69, 70, -1, 71, 72, -1, 73, -1, -1,
+ 74, 75, 76, -1, -1, 77, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, 78, -1, -1, 79, -1, -1, -1, -1, 80,
+ -1, 81, -1, 82, -1, 83, -1, -1, -1, 84, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 85, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, 86, -1, -1, -1, 87, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1, -1, -1, -1, 87, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, 88, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
- -1, 88
+ -1, 89
};
if (len <= MAX_WORD_LENGTH && len >= MIN_WORD_LENGTH)
@@ -408,6 +410,6 @@
}
return 0;
}
-#line 99 "ParameterHash.gperf"
+#line 100 "ParameterHash.gperf"
}
Index: resip/stack/Token.hxx
===================================================================
--- resip/stack/Token.hxx (.../branches/resiprocate-1.8) (revision 9855)
+++ resip/stack/Token.hxx (.../main) (revision 9855)
@@ -61,6 +61,7 @@
friend class _enum##_Param
defineParam(text, "text", ExistsOrDataParameter, "RFC 3840");
+ defineParam(cause, "cause", UInt32Parameter, "RFC 3326");
defineParam(dAlg, "d-alg", DataParameter, "RFC 3329");
defineParam(dQop, "d-qop", DataParameter, "RFC 3329");
defineParam(dVer, "d-ver", QuotedDataParameter, "RFC 3329");
Index: reSIProcate_9_0.sln
===================================================================
--- reSIProcate_9_0.sln (.../branches/resiprocate-1.8) (revision 9855)
+++ reSIProcate_9_0.sln (.../main) (revision 9855)
@@ -69,6 +69,10 @@
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "GeoIP", "contrib\GeoIP\GeoIP_9_0.vcproj", "{6527D843-EE53-4F1E-B0A9-12ABBA8E75CC}"
EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "repro", "repro", "{B649A6AA-0668-422C-9D84-0FDFC26E3A62}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "queuetostream", "repro\accountingconsumers\queuetostream_9_0.vcproj", "{02C11EC5-9AB9-44F1-9B60-B719C1728356}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Win32 = Debug|Win32
@@ -205,8 +209,23 @@
{6527D843-EE53-4F1E-B0A9-12ABBA8E75CC}.SSL-Debug|Win32.Build.0 = Debug|Win32
{6527D843-EE53-4F1E-B0A9-12ABBA8E75CC}.SSL-Release|Win32.ActiveCfg = Release|Win32
{6527D843-EE53-4F1E-B0A9-12ABBA8E75CC}.SSL-Release|Win32.Build.0 = Release|Win32
+ {02C11EC5-9AB9-44F1-9B60-B719C1728356}.Debug|Win32.ActiveCfg = Debug|Win32
+ {02C11EC5-9AB9-44F1-9B60-B719C1728356}.Debug|Win32.Build.0 = Debug|Win32
+ {02C11EC5-9AB9-44F1-9B60-B719C1728356}.Release|Win32.ActiveCfg = Release|Win32
+ {02C11EC5-9AB9-44F1-9B60-B719C1728356}.Release|Win32.Build.0 = Release|Win32
+ {02C11EC5-9AB9-44F1-9B60-B719C1728356}.SSL-Debug|Win32.ActiveCfg = SSL-Debug|Win32
+ {02C11EC5-9AB9-44F1-9B60-B719C1728356}.SSL-Debug|Win32.Build.0 = SSL-Debug|Win32
+ {02C11EC5-9AB9-44F1-9B60-B719C1728356}.SSL-Release|Win32.ActiveCfg = SSL-Release|Win32
+ {02C11EC5-9AB9-44F1-9B60-B719C1728356}.SSL-Release|Win32.Build.0 = SSL-Release|Win32
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
+ GlobalSection(NestedProjects) = preSolution
+ {9D8D2649-213F-49D3-A8B0-C1849C611654} = {B649A6AA-0668-422C-9D84-0FDFC26E3A62}
+ {16CD976A-5D3B-4329-88BA-A32560CDFCC8} = {B649A6AA-0668-422C-9D84-0FDFC26E3A62}
+ {31B0654F-E08E-405F-909F-80F86CB14B9E} = {B649A6AA-0668-422C-9D84-0FDFC26E3A62}
+ {02954DA6-5079-4717-BC3D-B3ACA815CFED} = {B649A6AA-0668-422C-9D84-0FDFC26E3A62}
+ {02C11EC5-9AB9-44F1-9B60-B719C1728356} = {B649A6AA-0668-422C-9D84-0FDFC26E3A62}
+ EndGlobalSection
EndGlobal
Index: repro/VERSION
===================================================================
--- repro/VERSION (.../branches/resiprocate-1.8) (revision 9855)
+++ repro/VERSION (.../main) (revision 9855)
@@ -1 +1 @@
-0.9
+1.9
Index: repro/reprolib_8_0.vcproj
===================================================================
--- repro/reprolib_8_0.vcproj (.../branches/resiprocate-1.8) (revision 9855)
+++ repro/reprolib_8_0.vcproj (.../main) (revision 9855)
@@ -42,7 +42,7 @@
<Tool
Name="VCCLCompilerTool"
Optimization="0"
- AdditionalIncludeDirectories=""$(ProjectDir)../";"$(ProjectDir)../resip/stack";"$(ProjectDir)../contrib/pcre""
+ AdditionalIncludeDirectories=""$(ProjectDir)../";"$(ProjectDir)../resip/stack";"$(ProjectDir)../contrib/pcre";"$(ProjectDir)../contrib/db/build_windows""
PreprocessorDefinitions="WIN32;_DEBUG;USE_ARES;USE_IPV6;LEAK_CHECK"
MinimalRebuild="false"
BasicRuntimeChecks="0"
@@ -106,7 +106,7 @@
/>
<Tool
Name="VCCLCompilerTool"
- AdditionalIncludeDirectories=""$(ProjectDir)../";"$(ProjectDir)../resip/stack";"$(ProjectDir)../contrib/pcre""
+ AdditionalIncludeDirectories=""$(ProjectDir)../";"$(ProjectDir)../resip/stack";"$(ProjectDir)../contrib/pcre";"$(ProjectDir)../contrib/db/build_windows""
PreprocessorDefinitions="WIN32;NDEBUG;USE_ARES;USE_IPV6"
MinimalRebuild="false"
RuntimeLibrary="2"
@@ -170,7 +170,7 @@
<Tool
Name="VCCLCompilerTool"
Optimization="0"
- AdditionalIncludeDirectories=""$(ProjectDir)../";"$(ProjectDir)../resip/stack";"$(ProjectDir)../contrib/pcre";"$(ProjectDir)../contrib/openssl/include";"$(ProjectDir)../contrib/openssl/inc32""
+ AdditionalIncludeDirectories=""$(ProjectDir)../";"$(ProjectDir)../resip/stack";"$(ProjectDir)../contrib/pcre";"$(ProjectDir)../contrib/openssl/include";"$(ProjectDir)../contrib/openssl/inc32";"$(ProjectDir)../contrib/db/build_windows""
PreprocessorDefinitions="WIN32;_DEBUG;USE_ARES;LEAK_CHECK;USE_IPV6;USE_SSL"
MinimalRebuild="false"
BasicRuntimeChecks="0"
@@ -234,7 +234,7 @@
/>
<Tool
Name="VCCLCompilerTool"
- AdditionalIncludeDirectories=""$(ProjectDir)../";"$(ProjectDir)../resip/stack";"$(ProjectDir)../contrib/pcre";"$(ProjectDir)../contrib/openssl/include";"$(ProjectDir)../contrib/openssl/inc32""
+ AdditionalIncludeDirectories=""$(ProjectDir)../";"$(ProjectDir)../resip/stack";"$(ProjectDir)../contrib/pcre";"$(ProjectDir)../contrib/openssl/include";"$(ProjectDir)../contrib/openssl/inc32";"$(ProjectDir)../contrib/db/build_windows""
PreprocessorDefinitions="WIN32;NDEBUG;USE_ARES;USE_IPV6;USE_SSL"
MinimalRebuild="false"
RuntimeLibrary="2"
@@ -297,6 +297,10 @@
>
</File>
<File
+ RelativePath=".\AccountingCollector.cxx"
+ >
+ </File>
+ <File
RelativePath=".\AclStore.cxx"
>
</File>
@@ -421,6 +425,10 @@
>
</File>
<File
+ RelativePath=".\PersistentMessageQueue.cxx"
+ >
+ </File>
+ <File
RelativePath=".\stateAgents\PrivateKeyPublicationHandler.cxx"
>
<FileConfiguration
@@ -587,6 +595,10 @@
>
</File>
<File
+ RelativePath=".\AccountingCollector.hxx"
+ >
+ </File>
+ <File
RelativePath=".\Ack200DoneMessage.hxx"
>
</File>
@@ -599,10 +611,6 @@
>
</File>
<File
- RelativePath=".\monkeys\CertificateAuthenticator.hxx"
- >
- </File>
- <File
RelativePath=".\AsyncProcessor.hxx"
>
</File>
@@ -615,6 +623,10 @@
>
</File>
<File
+ RelativePath=".\monkeys\CertificateAuthenticator.hxx"
+ >
+ </File>
+ <File
RelativePath=".\stateAgents\CertPublicationHandler.hxx"
>
</File>
@@ -687,6 +699,10 @@
>
</File>
<File
+ RelativePath=".\PersistentMessageQueue.hxx"
+ >
+ </File>
+ <File
RelativePath=".\stateAgents\PrivateKeyPublicationHandler.hxx"
>
</File>
@@ -811,6 +827,10 @@
>
</File>
<File
+ RelativePath=".\Worker.hxx"
+ >
+ </File>
+ <File
RelativePath=".\WorkerThread.hxx"
>
</File>
Index: repro/WebAdmin.cxx
===================================================================
--- repro/WebAdmin.cxx (.../branches/resiprocate-1.8) (revision 9855)
+++ repro/WebAdmin.cxx (.../main) (revision 9855)
@@ -1876,11 +1876,11 @@
localAddr.sin_addr.s_addr = htonl(INADDR_ANY);
localAddr.sin_port = 0;
- rc = bind(sd, (struct sockaddr *) &localAddr, sizeof(localAddr));
+ rc = ::bind(sd, (struct sockaddr *) &localAddr, sizeof(localAddr));
if(rc >= 0)
{
// Connect to server
- rc = connect(sd, (struct sockaddr *) &servAddr, sizeof(servAddr));
+ rc = ::connect(sd, (struct sockaddr *) &servAddr, sizeof(servAddr));
if(rc >= 0)
{
Data request("<Restart>\r\n <Request>\r\b </Request>\r\n</Restart>\r\n");
Index: repro/Registrar.cxx
===================================================================
--- repro/Registrar.cxx (.../branches/resiprocate-1.8) (revision 9855)
+++ repro/Registrar.cxx (.../main) (revision 9855)
@@ -3,6 +3,7 @@
#endif
#include "repro/Registrar.hxx"
+#include "repro/Proxy.hxx"
#include "resip/dum/ServerRegistration.hxx"
#include "rutil/Logger.hxx"
@@ -12,7 +13,7 @@
using namespace repro;
using namespace std;
-Registrar::Registrar()
+Registrar::Registrar() : mProxy(0)
{
}
@@ -39,6 +40,10 @@
}
if(continueProcessing)
{
+ if(mProxy)
+ {
+ mProxy->doRegistrationAccounting(AccountingCollector::RegistrationRefreshed, reg);
+ }
sr->accept();
}
}
@@ -56,6 +61,10 @@
}
if(continueProcessing)
{
+ if(mProxy)
+ {
+ mProxy->doRegistrationAccounting(AccountingCollector::RegistrationRemoved, reg);
+ }
sr->accept();
}
}
@@ -73,6 +82,10 @@
}
if(continueProcessing)
{
+ if(mProxy)
+ {
+ mProxy->doRegistrationAccounting(AccountingCollector::RegistrationRemovedAll, reg);
+ }
sr->accept();
}
}
@@ -90,6 +103,10 @@
}
if(continueProcessing)
{
+ if(mProxy)
+ {
+ mProxy->doRegistrationAccounting(AccountingCollector::RegistrationAdded, reg);
+ }
sr->accept();
}
}
Index: repro/ResponseContext.cxx
===================================================================
--- repro/ResponseContext.cxx (.../branches/resiprocate-1.8) (revision 9855)
+++ repro/ResponseContext.cxx (.../main) (revision 9855)
@@ -831,6 +831,9 @@
{
assert (request.isRequest());
+ // Do any required session accounting with this forward request - allows Session Routed event
+ mRequestContext.getProxy().doSessionAccounting(request, false /* received */, mRequestContext);
+
if (request.method() != CANCEL &&
request.method() != ACK)
{
Index: repro/AccountingCollector.hxx
===================================================================
--- repro/AccountingCollector.hxx (.../branches/resiprocate-1.8) (revision 0)
+++ repro/AccountingCollector.hxx (.../main) (revision 9855)
@@ -0,0 +1,129 @@
+#if !defined(RESIP_ACCOUNTINGCOLLECTOR_HXX)
+#define RESIP_ACCOUNTINGCOLLECTOR_HXX
+
+#include <memory>
+#include "rutil/ThreadIf.hxx"
+#include "rutil/TimeLimitFifo.hxx"
+#include "resip/stack/SipMessage.hxx"
+
+namespace json
+{
+ class Object;
+}
+
+namespace repro
+{
+class RequestContext;
+class PersistentMessageEnqueue;
+class ProxyConfig;
+
+class AccountingCollector : public resip::ThreadIf
+{
+public:
+ typedef enum
+ {
+ RegistrationAdded = 1,
+ RegistrationRefreshed = 2,
+ RegistrationRemoved = 3,
+ RegistrationRemovedAll = 4
+ } RegistrationEvent;
+
+ typedef enum
+ {
+ SessionCreated = 1,
+ SessionRouted = 2,
+ SessionRedirected = 3,
+ SessionEstablished = 4,
+ SessionCancelled = 5,
+ SessionEnded = 6,
+ SessionError = 7
+ } SessionEvent;
+
+ AccountingCollector(ProxyConfig& config);
+ virtual ~AccountingCollector();
+
+ virtual void doSessionAccounting(const resip::SipMessage& sip, bool received, RequestContext& context);
+ virtual void doRegistrationAccounting(RegistrationEvent regevent, const resip::SipMessage& sip);
+
+private:
+ resip::Data mDbBaseDir;
+ PersistentMessageEnqueue* mSessionEventQueue;
+ PersistentMessageEnqueue* mRegistrationEventQueue;
+ bool mSessionAccountingAddRoutingHeaders;
+ bool mSessionAccountingAddViaHeaders;
+ bool mRegistrationAccountingAddRoutingHeaders;
+ bool mRegistrationAccountingAddViaHeaders;
+ bool mRegistrationAccountingLogRefreshes;
+
+ virtual void thread();
+
+ enum FifoEventType
+ {
+ SessionEventType,
+ RegistrationEventType
+ };
+ class FifoEvent
+ {
+ public:
+ FifoEventType mType;
+ resip::Data mData;
+ };
+ resip::TimeLimitFifo<FifoEvent> mFifo;
+ PersistentMessageEnqueue* initializeEventQueue(FifoEventType type, bool destroyFirst=false);
+ void pushEventObjectToQueue(json::Object& object, FifoEventType type);
+ void internalProcess(std::auto_ptr<FifoEvent> eventData);
+};
+
+}
+
+#endif
+
+/* ====================================================================
+ * The Vovida Software License, Version 1.0
+ *
+ * Copyright (c) 2000 Vovida Networks, Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * 3. The names "VOCAL", "Vovida Open Communication Application Library",
+ * and "Vovida Open Communication Application Library (VOCAL)" must
+ * not be used to endorse or promote products derived from this
+ * software without prior written permission. For written
+ * permission, please contact vocal@xxxxxxxxxx.
+ *
+ * 4. Products derived from this software may not be called "VOCAL", nor
+ * may "VOCAL" appear in their name, without prior written
+ * permission of Vovida Networks, Inc.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESSED OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, TITLE AND
+ * NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT SHALL VOVIDA
+ * NETWORKS, INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT DAMAGES
+ * IN EXCESS OF $1,000, NOR FOR ANY INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
+ * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by Vovida
+ * Networks, Inc. and many individuals on behalf of Vovida Networks,
+ * Inc. For more information on Vovida Networks, Inc., please see
+ * <http://www.vovida.org/>.
+ *
+ */
Property changes on: repro/AccountingCollector.hxx
___________________________________________________________________
Added: svn:eol-style
+ native
Index: repro/PersistentMessageQueue.cxx
===================================================================
--- repro/PersistentMessageQueue.cxx (.../branches/resiprocate-1.8) (revision 0)
+++ repro/PersistentMessageQueue.cxx (.../main) (revision 9855)
@@ -0,0 +1,458 @@
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+//#include <fcntl.h>
+//#include <cassert>
+//#include <cstdlib>
+
+#include "rutil/Data.hxx"
+#include "rutil/FileSystem.hxx"
+#include "rutil/Logger.hxx"
+
+#include "repro/PersistentMessageQueue.hxx"
+#include "rutil/WinLeakCheck.hxx"
+
+using namespace resip;
+using namespace repro;
+using namespace std;
+
+#define RESIPROCATE_SUBSYSTEM Subsystem::REPRO
+
+struct Transaction
+{
+ Transaction() : mDbTxn(0)
+ {
+ }
+
+ void init(DbEnv * dbenv)
+ {
+ // let caller catch exceptions
+ dbenv->txn_begin(NULL, &mDbTxn, 0);
+ }
+
+ ~Transaction()
+ {
+ abort();
+ }
+
+ void abort()
+ {
+ // don't throw exceptions since this is called in destructor
+ if(mDbTxn !=0 )
+ {
+ try
+ {
+ mDbTxn->abort();
+ }
+ catch(DbException&) {}
+ catch(std::exception&) {}
+ catch(...) {}
+
+ mDbTxn = 0;
+ }
+ }
+
+ void commit()
+ {
+ // let caller catch exceptions
+ if(mDbTxn !=0 )
+ {
+ mDbTxn->commit(0);
+ mDbTxn = 0;
+ }
+ }
+
+ DbTxn* mDbTxn;
+};
+
+struct Cursor
+{
+ Cursor() : mDbc(0)
+ {
+ }
+
+ void init(Db* db, DbTxn* t)
+ {
+ // let caller catch exceptions
+ db->cursor(t, &mDbc, 0);
+ }
+
+ ~Cursor()
+ {
+ close();
+ }
+
+ void close()
+ {
+ // don't throw exceptions since this is called in destructor
+ if(mDbc)
+ {
+ try
+ {
+ mDbc->close();
+ }
+ catch(DbException&) {}
+ catch(std::exception&) {}
+ catch(...) {}
+
+ mDbc = 0;
+ }
+ }
+
+ Dbc* mDbc;
+};
+
+PersistentMessageQueue::PersistentMessageQueue(const Data& baseDir) :
+ DbEnv(0),
+ mDb(0),
+ mBaseDir(baseDir),
+ mRecoveryNeeded(false)
+{
+}
+
+PersistentMessageQueue::~PersistentMessageQueue()
+{
+ if(mDb)
+ {
+ try
+ {
+ mDb->close(0);
+ }
+ catch(DbException&) {}
+ catch(std::exception&) {}
+ catch(...) {}
+ }
+
+ try
+ {
+ delete mDb;
+ close(0);
+ }
+ catch(DbException&) {}
+ catch(std::exception&) {}
+ catch(...) {}
+}
+
+bool
+PersistentMessageQueue::init(bool sync, const resip::Data& queueName)
+{
+ try
+ {
+ // For Berkeley DB Concurrent Data Store applications, perform locking on an environment-wide basis rather than per-database.
+ set_flags(DB_CDB_ALLDB, 1);
+
+ if(sync)
+ {
+ // Write changes to disk on transaction commit
+ set_flags(DB_TXN_NOSYNC, 0);
+ }
+ else
+ {
+ set_flags(DB_TXN_NOSYNC, 1);
+ }
+
+ Data homeDir;
+ if (mBaseDir.postfix("/") ||
+ mBaseDir.postfix("\\") ||
+ mBaseDir.empty())
+ {
+ homeDir = mBaseDir + queueName;
+ }
+ else
+ {
+ homeDir = mBaseDir + Data("/") + queueName;
+ }
+
+ // Create directory if it doesn't exist
+ FileSystem::Directory dir(homeDir);
+ dir.create();
+
+ open(homeDir.c_str(), // home directory
+ DB_INIT_LOCK // Initialize Locking (needed for transactions)
+ | DB_INIT_LOG // Initialize Logging (needed for transactions)
+ | DB_INIT_TXN // Initialize transactions
+ | DB_INIT_MPOOL // Initialize the cache (needed for transactions)
+ | DB_REGISTER // Check to see if recovery needs to be performed before opening the database environment
+ | DB_RECOVER // Run normal recovery
+ | DB_CREATE // If the env does not exist, then create it
+ | DB_THREAD, // Free-thread the env handle
+ 0); // mode
+
+ mDb = new Db(this, 0);
+
+ // cause the logical record numbers to be mutable, and change as records are added to and deleted from the database.
+ mDb->set_flags(DB_RENUMBER);
+
+ mDb->open(0, // txnid
+ "msgqueue", // filename
+ 0, // database name
+ DB_RECNO, // database type
+ DB_AUTO_COMMIT // enclose db->open within a transaction
+ | DB_CREATE // create the database if it doesn't already exist
+ | DB_THREAD, // allow free-threaded db access
+ 0); // mode
+
+ return true;
+ }
+ catch(DbException& e)
+ {
+ if(e.get_errno() == DB_RUNRECOVERY)
+ {
+ mRecoveryNeeded = true;
+ }
+ WarningLog( << "PersistentMessageQueue::init - DBException: " << e.what());
+ }
+ catch(std::exception& e)
+ {
+ WarningLog( << "PersistentMessageQueue::init - std::exception: " << e.what());
+ }
+ catch(...)
+ {
+ WarningLog( << "PersistentMessageQueue::init - unknown exception");
+ }
+
+ return false;
+}
+
+bool
+PersistentMessageQueue::isRecoveryNeeded()
+{
+ return mRecoveryNeeded;
+}
+
+bool
+PersistentMessageEnqueue::push(const resip::Data& data)
+{
+ int res;
+
+ try
+ {
+ Transaction transaction;
+ transaction.init(this);
+
+ db_recno_t recno;
+ recno = 0;
+ Dbt val((void*)data.c_str(), data.size());
+ Dbt key((void*)&recno, sizeof(recno));
+
+ key.set_ulen(sizeof(recno));
+ key.set_flags(DB_DBT_USERMEM);
+
+ res = mDb->put(transaction.mDbTxn, &key, &val, DB_APPEND);
+ if(res == 0)
+ {
+ transaction.commit();
+ return true;
+ }
+ else
+ {
+ WarningLog( << "PersistentMessageEnqueue::push - put failed: " << db_strerror(res));
+ return false;
+ }
+ }
+ catch(DbException& e)
+ {
+ if(e.get_errno() == DB_RUNRECOVERY)
+ {
+ mRecoveryNeeded = true;
+ }
+ WarningLog( << "PersistentMessageEnqueue::push - DBException: " << e.what());
+ }
+ catch(std::exception& e)
+ {
+ WarningLog( << "PersistentMessageEnqueue::push - std::exception: " << e.what());
+ }
+ catch(...)
+ {
+ WarningLog( << "PersistentMessageEnqueue::push - unknown exception");
+ }
+ return false;
+}
+
+// returns true for success, false for failure - can return true and 0 records if none available
+// Note: if autoCommit is used then it is safe to allow multiple consumers
+bool
+PersistentMessageDequeue::pop(size_t numRecords, std::vector<resip::Data>& records, bool autoCommit)
+{
+ if(mNumRecords != 0) // TODO, warning previous pop wasn't committed
+ {
+ abort();
+ }
+ records.clear();
+
+ // Get a cursor and Read
+ try
+ {
+ Transaction transaction; // Only used with auto-commit
+ Cursor cursor;
+ if(autoCommit)
+ {
+ transaction.init(this);
+ }
+ cursor.init(mDb, transaction.mDbTxn); // If autoCommit is false then mDbTxn is 0
+
+ Dbt val;
+ db_recno_t recno = 0;
+ Dbt key((void*)&recno, sizeof(recno));
+
+ for(size_t i = 0; i < numRecords; i ++ )
+ {
+ int get_res = cursor.mDbc->get(&key, &val, DB_NEXT | (autoCommit ? DB_RMW : 0));
+
+ if(get_res == 0)
+ {
+ records.push_back(Data((const char *)val.get_data(), val.get_size()));
+ if(autoCommit)
+ {
+ cursor.mDbc->del(0);
+ }
+ }
+ else
+ {
+ break;
+ }
+ }
+
+ cursor.close();
+ if(autoCommit)
+ {
+ transaction.commit();
+ }
+ else
+ {
+ mNumRecords = records.size();
+ }
+ return true;
+ }
+ catch(DbException& e)
+ {
+ if(e.get_errno() == DB_RUNRECOVERY)
+ {
+ mRecoveryNeeded = true;
+ }
+ WarningLog( << "PersistentMessageDequeue::pop - DBException: " << e.what());
+ abort();
+ return false;
+ }
+ catch(std::exception& e)
+ {
+ WarningLog( << "PersistentMessageDequeue::pop - std::exception: " << e.what());
+ abort();
+ return false;
+ }
+ catch(...)
+ {
+ WarningLog( << "PersistentMessageDequeue::pop - unknown exception");
+ }
+}
+
+bool
+PersistentMessageDequeue::commit()
+{
+ if(mNumRecords == 0)
+ {
+ return true;
+ }
+
+ // Read and delete
+ try
+ {
+ Transaction transaction;
+ Cursor cursor;
+
+ transaction.init(this);
+ cursor.init(mDb, transaction.mDbTxn);
+
+ Dbt val;
+ db_recno_t recno = 0;
+ Dbt key((void*)&recno, sizeof(recno));
+
+ for(size_t i = 0; i < mNumRecords; i++)
+ {
+ int get_res = cursor.mDbc->get(&key, &val, DB_NEXT | DB_RMW);
+ if(get_res == 0)
+ {
+ cursor.mDbc->del(0);
+ }
+ else
+ {
+ break; // this is bad!
+ }
+ }
+
+ mNumRecords = 0;
+ cursor.close();
+ transaction.commit();
+
+ return true;
+ }
+ catch(DbException& e)
+ {
+ if(e.get_errno() == DB_RUNRECOVERY)
+ {
+ mRecoveryNeeded = true;
+ }
+ WarningLog( << "PersistentMessageDequeue::commit - DBException: " << e.what());
+ }
+ catch(std::exception& e)
+ {
+ WarningLog( << "PersistentMessageDequeue::commit - std::exception: " << e.what());
+ }
+ catch(...)
+ {
+ WarningLog( << "PersistentMessageDequeue::commit - unknown exception");
+ }
+ return false;
+}
+
+void
+PersistentMessageDequeue::abort()
+{
+ mNumRecords = 0;
+}
+
+
+/* ====================================================================
+ * The Vovida Software License, Version 1.0
+ *
+ * Copyright (c) 2000 Vovida Networks, Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * 3. The names "VOCAL", "Vovida Open Communication Application Library",
+ * and "Vovida Open Communication Application Library (VOCAL)" must
+ * not be used to endorse or promote products derived from this
+ * software without prior written permission. For written
+ * permission, please contact vocal@xxxxxxxxxx.
+ *
+ * 4. Products derived from this software may not be called "VOCAL", nor
+ * may "VOCAL" appear in their name, without prior written
+ * permission of Vovida Networks, Inc.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESSED OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, TITLE AND
+ * NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT SHALL VOVIDA
+ * NETWORKS, INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT DAMAGES
+ * IN EXCESS OF $1,000, NOR FOR ANY INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
+ * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *
+ * ====================================================================
+ */
Property changes on: repro/PersistentMessageQueue.cxx
___________________________________________________________________
Added: svn:eol-style
+ native
Index: repro/Proxy.cxx
===================================================================
--- repro/Proxy.cxx (.../branches/resiprocate-1.8) (revision 9855)
+++ repro/Proxy.cxx (.../main) (revision 9855)
@@ -91,7 +91,10 @@
mTargetProcessorChain(targetP),
mUserStore(config.getDataStore()->mUserStore),
mOptionsHandler(0),
- mRequestContextFactory(new RequestContextFactory)
+ mRequestContextFactory(new RequestContextFactory),
+ mSessionAccountingEnabled(config.getConfigBool("SessionAccountingEnabled", false)),
+ mRegistrationAccountingEnabled(config.getConfigBool("RegistrationAccountingEnabled", false)),
+ mAccountingCollector(0)
{
FlowTokenSalt = Random::getCryptoRandom(20); // 20-octet Crypto Random Key for Salting Flow Token HMACs
@@ -101,6 +104,12 @@
{
addSupportedOption("outbound");
}
+
+ // Create Accounting Collector if enabled
+ if(mSessionAccountingEnabled || mRegistrationAccountingEnabled)
+ {
+ mAccountingCollector = new AccountingCollector(config);
+ }
}
@@ -108,6 +117,7 @@
{
shutdown();
join();
+ delete mAccountingCollector;
InfoLog (<< "Proxy::thread shutdown with " << mServerRequestContexts.size() << " ServerRequestContexts and " << mClientRequestContexts.size() << " ClientRequestContexts.");
}
@@ -621,8 +631,27 @@
mSupportedOptions.erase(option);
}
+void
+Proxy::doSessionAccounting(const resip::SipMessage& sip, bool received, RequestContext& context)
+{
+ if(mSessionAccountingEnabled)
+ {
+ assert(mAccountingCollector);
+ mAccountingCollector->doSessionAccounting(sip, received, context);
+ }
+}
+void
+Proxy::doRegistrationAccounting(AccountingCollector::RegistrationEvent regEvent, const resip::SipMessage& sip)
+{
+ if(mRegistrationAccountingEnabled)
+ {
+ assert(mAccountingCollector);
+ mAccountingCollector->doRegistrationAccounting(regEvent, sip);
+ }
+}
+
/* ====================================================================
* The Vovida Software License, Version 1.0
*
Index: repro/monkeys/StrictRouteFixup.cxx
===================================================================
--- repro/monkeys/StrictRouteFixup.cxx (.../branches/resiprocate-1.8) (revision 9855)
+++ repro/monkeys/StrictRouteFixup.cxx (.../main) (revision 9855)
@@ -52,6 +52,9 @@
return SkipAllChains;
}
+ // Do any required session accounting
+ context.getProxy().doSessionAccounting(request, true /* received */, context);
+
//Will cancel any active transactions (ideally there should be none)
//and terminate any pending transactions.
context.getResponseContext().cancelAllClientTransactions();
Index: repro/monkeys/GeoProximityTargetSorter.cxx
===================================================================
--- repro/monkeys/GeoProximityTargetSorter.cxx (.../branches/resiprocate-1.8) (revision 9855)
+++ repro/monkeys/GeoProximityTargetSorter.cxx (.../main) (revision 9855)
@@ -40,6 +40,9 @@
// Geo IP tables is not required
static ExtensionParameter p_geolocation("x-repro-geolocation");
+void* GeoProximityTargetSorter::mGeoIPv4 = 0;
+void* GeoProximityTargetSorter::mGeoIPv6 = 0;
+
class GeoProximityTargetContainer
{
public:
@@ -66,9 +69,7 @@
mRUriRegularExpressionData(config.getConfigData("GeoProximityRequestUriFilter", "")),
mRUriRegularExpression(0),
mDefaultDistance(config.getConfigUnsignedLong("GeoProximityDefaultDistance", 0)),
- mLoadBalanceEqualDistantTargets(config.getConfigBool("LoadBalanceEqualDistantTargets", true)),
- mGeoIPv4(0),
- mGeoIPv6(0)
+ mLoadBalanceEqualDistantTargets(config.getConfigBool("LoadBalanceEqualDistantTargets", true))
{
int flags = REG_EXTENDED | REG_NOSUB;
@@ -97,6 +98,8 @@
mGeoIPv4 = (GeoIP*)GeoIP_open(geoIPv4Database.c_str(), GEOIP_MEMORY_CACHE); // Cache entire DB in memory - could make this configurable
if(mGeoIPv4 != 0)
{
+ InfoLog(<< "GeoProximityTargetSorter: IPv4 db info: " << GeoIP_database_info((GeoIP*)mGeoIPv4));
+
int i = GeoIP_database_edition((GeoIP*)mGeoIPv4);
if(i != GEOIP_CITY_EDITION_REV0 /* 6 */ &&
@@ -127,6 +130,8 @@
mGeoIPv6 = (GeoIP*)GeoIP_open(geoIPv6Database.c_str(), GEOIP_MEMORY_CACHE); // Cache entire DB in memory - could make this configurable
if(mGeoIPv6 != 0)
{
+ InfoLog(<< "GeoProximityTargetSorter: IPv6 db info: " << GeoIP_database_info((GeoIP*)mGeoIPv6));
+
int i = GeoIP_database_edition((GeoIP*)mGeoIPv6);
if(i != GEOIP_CITY_EDITION_REV1_V6 /* 30 */ &&
@@ -320,19 +325,17 @@
}
}
+ // If we cannot determine geo location of target - then return 0,0
+ latitude = 0;
+ longitude = 0;
+
// Next - try and find the public IP of the client that sent the request
Tuple publicAddress = Helper::getClientPublicAddress(request);
if(publicAddress.getType() != UNKNOWN_TRANSPORT)
{
// Do a MaxMind GeoIP lookup to determine latitude and longitude
- geoIPLookup(publicAddress, latitude, longitude);
+ geoIPLookup(publicAddress, &latitude, &longitude);
}
- else
- {
- // Cannot determine geo location of target - return 0,0
- latitude = 0;
- longitude = 0;
- }
}
void
@@ -345,11 +348,15 @@
return;
}
+ // If we cannot determine geo location of client - then return 0,0
+ latitude = 0;
+ longitude = 0;
+
// Next - see if we stored a public IP of the client at registration time
if(target.rec().mPublicAddress.getType() != UNKNOWN_TRANSPORT)
{
// Do a MaxMind GeoIP lookup to determine latitude and longitude
- geoIPLookup(target.rec().mPublicAddress, latitude, longitude);
+ geoIPLookup(target.rec().mPublicAddress, &latitude, &longitude);
}
else
{
@@ -358,14 +365,8 @@
if(!contactAddress.isPrivateAddress())
{
// Do a MaxMind GeoIP lookup to determine latitude and longitude
- geoIPLookup(contactAddress, latitude, longitude);
+ geoIPLookup(contactAddress, &latitude, &longitude);
}
- else
- {
- // Cannot determine geo location of client - return 0,0
- latitude = 0;
- longitude = 0;
- }
}
}
@@ -434,7 +435,7 @@
}
bool
-GeoProximityTargetSorter::geoIPLookup(const Tuple& address, double& latitude, double& longitude)
+GeoProximityTargetSorter::geoIPLookup(const Tuple& address, double* latitude, double* longitude, Data* country, Data* region, Data* city)
{
#ifdef USE_MAXMIND_GEOIP
GeoIPRecord *gir = 0;
@@ -456,14 +457,20 @@
if(gir != 0)
{
- latitude = gir->latitude;
- longitude = gir->longitude;
+ Data countryData(Data::Share, gir->country_code ? gir->country_code : "");
+ Data regionData(Data::Share, gir->region ? gir->region : "");
+ Data cityData(Data::Share, gir->city ? gir->city : "");
+ if(latitude) *latitude = gir->latitude;
+ if(longitude) *longitude = gir->longitude;
+ if(country) *country = countryData;
+ if(region) *region = regionData;
+ if(city) *city = cityData;
DebugLog(<< "GeoProximityTargetSorter::geoIPLookup: Tuple=" << address
- << ", Country=" << Data(gir->country_code)
- << ", Region=" << Data(gir->region)
- << ", City=" << Data(gir->city)
- << ", Lat/Long=" << latitude << "/" << longitude);
+ << ", Country=" << countryData
+ << ", Region=" << regionData
+ << ", City=" << cityData
+ << ", Lat/Long=" << gir->latitude << "/" << gir->longitude);
GeoIPRecord_delete(gir);
return true;
@@ -474,8 +481,6 @@
}
#endif
- latitude = 0;
- longitude = 0;
return false;
}
Index: repro/monkeys/GeoProximityTargetSorter.hxx
===================================================================
--- repro/monkeys/GeoProximityTargetSorter.hxx (.../branches/resiprocate-1.8) (revision 9855)
+++ repro/monkeys/GeoProximityTargetSorter.hxx (.../main) (revision 9855)
@@ -82,22 +82,35 @@
virtual ~GeoProximityTargetSorter();
virtual processor_action_t process(RequestContext &);
-
+
+ // static fn available for other parts of repro to access the geoip library
+ // fills in any non-null field
+ static bool geoIPLookup(const resip::Tuple& address,
+ double* latitude,
+ double* longitude,
+ resip::Data* country=0,
+ resip::Data* region=0,
+ resip::Data* city=0);
+
protected:
void getClientGeoLocation(const resip::SipMessage& request, double& latitude, double& longitude);
void getTargetGeoLocation(const Target& target, double& latitude, double& longitude);
double getTargetDistance(const Target& target, double clientLatitude, double clientLongitude);
void parseGeoLocationParameter(const resip::Data& parameter, double& latitude, double& longitude);
double calculateDistance(double latitude1, double longitude1, double latitude2, double longitude2);
- bool geoIPLookup(const resip::Tuple& address, double& latitude, double& longitude);
resip::Data mRUriRegularExpressionData;
regex_t* mRUriRegularExpression;
unsigned long mDefaultDistance;
bool mLoadBalanceEqualDistantTargets;
- void* mGeoIPv4;
- void* mGeoIPv6;
+
+ // Use static instance of the GeoIP library
+ // - allows static geoIPLookup method
+ // - reduces memory in cases where multiple instances of GeoProximityTargetSorter are needed
+ // (take care when creating multipleinstances since static initialization is not mutexed)
+ static void* mGeoIPv4;
+ static void* mGeoIPv6;
};
}
Index: repro/monkeys/CertificateAuthenticator.hxx
===================================================================
--- repro/monkeys/CertificateAuthenticator.hxx (.../branches/resiprocate-1.8) (revision 9855)
+++ repro/monkeys/CertificateAuthenticator.hxx (.../main) (revision 9855)
@@ -4,8 +4,8 @@
#include <set>
#include "rutil/Data.hxx"
+#include "rutil/KeyValueStore.hxx"
#include "resip/dum/TlsPeerAuthManager.hxx"
-#include "rutil/KeyValueStore.hxx"
#include "repro/Processor.hxx"
#include "repro/Dispatcher.hxx"
#include "repro/ProxyConfig.hxx"
Index: repro/monkeys/AmIResponsible.cxx
===================================================================
--- repro/monkeys/AmIResponsible.cxx (.../branches/resiprocate-1.8) (revision 9855)
+++ repro/monkeys/AmIResponsible.cxx (.../main) (revision 9855)
@@ -32,6 +32,10 @@
resip::SipMessage& request = context.getOriginalRequest();
+ // This call is placed after the DigestAuthenticator, so that we only account for
+ // authenticated sessions.
+ context.getProxy().doSessionAccounting(request, true /* received */, context);
+
// There should be no Routes on the request at this point, if there was a route, then
// the StrictRouteFixup monkey would have routed to it already
assert (!request.exists(h_Routes) ||
Index: repro/reprolib_9_0.vcproj
===================================================================
--- repro/reprolib_9_0.vcproj (.../branches/resiprocate-1.8) (revision 9855)
+++ repro/reprolib_9_0.vcproj (.../main) (revision 9855)
@@ -44,7 +44,7 @@
Name="VCCLCompilerTool"
AdditionalOptions="/MP"
Optimization="0"
- AdditionalIncludeDirectories=""$(ProjectDir)../";"$(ProjectDir)../resip/stack";"$(ProjectDir)../contrib/pcre";"$(ProjectDir)../contrib/GeoIP/libGeoIP";"$(ProjectDir)../contrib/MySQLConnectorC/include""
+ AdditionalIncludeDirectories=""$(ProjectDir)../";"$(ProjectDir)../resip/stack";"$(ProjectDir)../contrib/pcre";"$(ProjectDir)../contrib/GeoIP/libGeoIP";"$(ProjectDir)../contrib/MySQLConnectorC/include";"$(ProjectDir)../contrib/db/build_windows""
PreprocessorDefinitions="WIN32;_DEBUG;USE_ARES;USE_IPV6;LEAK_CHECK;;USE_MYSQL;USE_MAXMIND_GEOIP"
MinimalRebuild="false"
BasicRuntimeChecks="0"
@@ -109,7 +109,7 @@
<Tool
Name="VCCLCompilerTool"
AdditionalOptions="/MP"
- AdditionalIncludeDirectories=""$(ProjectDir)../";"$(ProjectDir)../resip/stack";"$(ProjectDir)../contrib/pcre";"$(ProjectDir)../contrib/GeoIP/libGeoIP";"$(ProjectDir)../contrib/MySQLConnectorC/include""
+ AdditionalIncludeDirectories=""$(ProjectDir)../";"$(ProjectDir)../resip/stack";"$(ProjectDir)../contrib/pcre";"$(ProjectDir)../contrib/GeoIP/libGeoIP";"$(ProjectDir)../contrib/MySQLConnectorC/include";"$(ProjectDir)../contrib/db/build_windows""
PreprocessorDefinitions="WIN32;NDEBUG;USE_ARES;USE_IPV6;USE_MYSQL;USE_MAXMIND_GEOIP"
MinimalRebuild="false"
RuntimeLibrary="2"
@@ -174,7 +174,7 @@
Name="VCCLCompilerTool"
AdditionalOptions="/MP"
Optimization="0"
- AdditionalIncludeDirectories=""$(ProjectDir)../";"$(ProjectDir)../resip/stack";"$(ProjectDir)../contrib/pcre";"$(ProjectDir)../contrib/openssl/include";"$(ProjectDir)../contrib/openssl/inc32";"$(ProjectDir)../contrib/GeoIP/libGeoIP";"$(ProjectDir)../contrib/MySQLConnectorC/include""
+ AdditionalIncludeDirectories=""$(ProjectDir)../";"$(ProjectDir)../resip/stack";"$(ProjectDir)../contrib/pcre";"$(ProjectDir)../contrib/openssl/include";"$(ProjectDir)../contrib/openssl/inc32";"$(ProjectDir)../contrib/GeoIP/libGeoIP";"$(ProjectDir)../contrib/MySQLConnectorC/include";"$(ProjectDir)../contrib/db/build_windows""
PreprocessorDefinitions="WIN32;_DEBUG;USE_ARES;LEAK_CHECK;USE_IPV6;USE_SSL;USE_MYSQL;USE_MAXMIND_GEOIP"
MinimalRebuild="false"
BasicRuntimeChecks="0"
@@ -239,7 +239,7 @@
<Tool
Name="VCCLCompilerTool"
AdditionalOptions="/MP"
- AdditionalIncludeDirectories=""$(ProjectDir)../";"$(ProjectDir)../resip/stack";"$(ProjectDir)../contrib/pcre";"$(ProjectDir)../contrib/openssl/include";"$(ProjectDir)../contrib/openssl/inc32";"$(ProjectDir)../contrib/GeoIP/libGeoIP";"$(ProjectDir)../contrib/MySQLConnectorC/include""
+ AdditionalIncludeDirectories=""$(ProjectDir)../";"$(ProjectDir)../resip/stack";"$(ProjectDir)../contrib/pcre";"$(ProjectDir)../contrib/openssl/include";"$(ProjectDir)../contrib/openssl/inc32";"$(ProjectDir)../contrib/GeoIP/libGeoIP";"$(ProjectDir)../contrib/MySQLConnectorC/include";"$(ProjectDir)../contrib/db/build_windows""
PreprocessorDefinitions="WIN32;NDEBUG;USE_ARES;USE_IPV6;USE_SSL;USE_MYSQL;USE_MAXMIND_GEOIP"
MinimalRebuild="false"
RuntimeLibrary="2"
@@ -305,6 +305,10 @@
>
</File>
<File
+ RelativePath=".\AccountingCollector.cxx"
+ >
+ </File>
+ <File
RelativePath=".\AclStore.cxx"
>
</File>
@@ -421,6 +425,10 @@
>
</File>
<File
+ RelativePath=".\PersistentMessageQueue.cxx"
+ >
+ </File>
+ <File
RelativePath=".\stateAgents\PrivateKeyPublicationHandler.cxx"
>
<FileConfiguration
@@ -587,6 +595,10 @@
>
</File>
<File
+ RelativePath=".\AccountingCollector.hxx"
+ >
+ </File>
+ <File
RelativePath=".\Ack200DoneMessage.hxx"
>
</File>
@@ -599,10 +611,6 @@
>
</File>
<File
- RelativePath=".\monkeys\CertificateAuthenticator.hxx"
- >
- </File>
- <File
RelativePath=".\AsyncProcessor.hxx"
>
</File>
@@ -615,6 +623,10 @@
>
</File>
<File
+ RelativePath=".\monkeys\CertificateAuthenticator.hxx"
+ >
+ </File>
+ <File
RelativePath=".\stateAgents\CertPublicationHandler.hxx"
>
</File>
@@ -679,6 +691,10 @@
>
</File>
<File
+ RelativePath=".\PersistentMessageQueue.hxx"
+ >
+ </File>
+ <File
RelativePath=".\stateAgents\PrivateKeyPublicationHandler.hxx"
>
</File>
@@ -803,6 +819,10 @@
>
</File>
<File
+ RelativePath=".\Worker.hxx"
+ >
+ </File>
+ <File
RelativePath=".\WorkerThread.hxx"
>
</File>
Index: repro/repro.config
===================================================================
--- repro/repro.config (.../branches/resiprocate-1.8) (revision 9855)
+++ repro/repro.config (.../main) (revision 9855)
@@ -253,6 +253,67 @@
# sip_domain = '$domain' AND account_status = 'active'
MySQLCustomUserAuthQuery =
+# Session Accounting - When enabled resiprocate will push a JSON formatted
+# events for sip session related messaging that the proxy receives,
+# to a persistent message queue that uses berkeleydb backed storage.
+# The following session events are logged:
+# Session Created - INVITE passing authentication was received
+# Session Routed - received INVITE was forward to a target
+# Session Redirected - session was 3xx redirected or REFERed
+# Session Established - there was 2xx answer to an INVITE (only generate for first 2xx)
+# Session Cancelled - CANCEL was received
+# Session Ended - BYE was received from either end
+# Session Error - a 4xx, 5xx, or 6xx response was sent to the inviter
+# Consuming Accounting Events:
+# Users must ensure that this message queue is consumed, or it will grow without
+# bound. A queuetostream consumer process is provided, that will consume the
+# events from the message queue and stream them to stdout. This output stream can
+# be consumed by linux scripting tools and converted to database records or some
+# other relevant representation of the data.
+# For example: ./queuetostream ./sessioneventqueue > streamconsumer
+# In the future a MySQL consumer may also be provided in order to update
+# session accounting records in a MySQL database table.
+SessionAccountingEnabled = false
+
+# The following setting determines if repro will add routing header information
+# (ie. Route, and Record-Route headers)to the Session Created, Session Routed
+# and Session Established events.
+SessionAccountingAddRoutingHeaders = false
+
+# The following setting determines if we will add via header information to
+# the Session Created event.
+SessionAccountingAddViaHeaders = false
+
+# Registration Accounting - When enabled resiprocate will push a JSON formatted
+# events for every registration, re-registration, and unregistration message
+# received to a persistent message queue that uses berkeleydb backed storage.
+# The following registration events are logged:
+# Registration Added - initial registration received
+# Registration Refreshed - registration refresh received / re-register
+# Registration Removed - registration removed by client / unregister
+# Registration Removed All - all contacts registration remove / unregister
+# Consuming Accounting Events:
+# Users must ensure that this message queue is consumed, or it will grow without
+# bound. A queuetostream consumer process is provided, that will consume the
+# events from the message queue and stream them to stdout. This output stream can
+# be consumed by linux scripting tools and converted to database records or some
+# other relevant representation of the data.
+# For example: ./queuetostream ./regeventqueue > streamconsumer
+# In the future a MySQL consumer may also be provided in order to update
+# login/registration accounting records in a MySQL database table.
+RegistrationAccountingEnabled = false
+
+# The following setting determines if repro will add routing header information
+# (ie. Route and Path headers)to registration accounting events.
+RegistrationAccountingAddRoutingHeaders = false
+
+# The following setting determines if we will add via header information to
+# the registration accounting events.
+RegistrationAccountingAddViaHeaders = false
+
+# The following setting determines if we log the RegistrationRefreshed events
+RegistrationAccountingLogRefreshes = false
+
# Run a Certificate Server - Allows PUBLISH and SUBSCRIBE for certificates
EnableCertServer = false
@@ -617,7 +678,7 @@
# This setting specifies a PCRE compliant regular expression to attempt
# to match against the request URI of inbound requests. Any requests
-# matching this expression, will have its Targets sorted as described
+# matching this expression, will have their targets sorted as described
# above. Leave blank to match all requests.
GeoProximityRequestUriFilter = ^sip:mediaserver.*@mydomain.com$
Index: repro/RequestContext.cxx
===================================================================
--- repro/RequestContext.cxx (.../branches/resiprocate-1.8) (revision 9855)
+++ repro/RequestContext.cxx (.../main) (revision 9855)
@@ -46,6 +46,8 @@
mProxy(proxy),
mResponseContext(*this),
mTCSerial(0),
+ mSessionCreatedEventSent(false),
+ mSessionEstablishedEventSent(false),
mKeyValueStore(*Proxy::getRequestKeyValueStoreKeyAllocator())
{
mInitialTimerCSet=false;
@@ -220,6 +222,10 @@
{
if(msg->method()==CANCEL)
{
+ if(mSessionCreatedEventSent && !mSessionEstablishedEventSent)
+ {
+ getProxy().doSessionAccounting(*msg, true /* received */, *this);
+ }
mResponseContext.processCancel(*msg);
doPostProcess=true;
}
@@ -962,6 +968,10 @@
{
msg.header(h_Server).value() = serverText;
}
+ if(mSessionCreatedEventSent && !mSessionEstablishedEventSent)
+ {
+ getProxy().doSessionAccounting(msg, false /* received */, *this);
+ }
send(msg);
}
}
Index: repro/ReproRunner.cxx
===================================================================
--- repro/ReproRunner.cxx (.../branches/resiprocate-1.8) (revision 9855)
+++ repro/ReproRunner.cxx (.../main) (revision 9855)
@@ -830,6 +830,10 @@
// like a catchall and will handle all requests the DUM does not
mSipStack->registerTransactionUser(*mProxy);
+ if(mRegistrar)
+ {
+ mRegistrar->setProxy(mProxy);
+ }
return true;
}
Index: repro/reprolib_10_0.vcxproj
===================================================================
--- repro/reprolib_10_0.vcxproj (.../branches/resiprocate-1.8) (revision 9855)
+++ repro/reprolib_10_0.vcxproj (.../main) (revision 9855)
@@ -163,7 +163,7 @@
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<ClCompile>
<Optimization>Disabled</Optimization>
- <AdditionalIncludeDirectories>$(ProjectDir)../;$(ProjectDir)../resip/stack;$(ProjectDir)../contrib/pcre;$(ProjectDir)../contrib/GeoIP/libGeoIP;$(ProjectDir)../contrib/MySQLConnectorC/include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ <AdditionalIncludeDirectories>$(ProjectDir)../;$(ProjectDir)../resip/stack;$(ProjectDir)../contrib/pcre;$(ProjectDir)../contrib/GeoIP/libGeoIP;$(ProjectDir)../contrib/MySQLConnectorC/include;$(ProjectDir)../contrib/db/build_windows;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>WIN32;_DEBUG;USE_ARES;USE_IPV6;USE_MYSQL;USE_MAXMIND_GEOIP;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<MinimalRebuild>false</MinimalRebuild>
<BasicRuntimeChecks>
@@ -179,7 +179,7 @@
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<ClCompile>
<Optimization>Disabled</Optimization>
- <AdditionalIncludeDirectories>$(ProjectDir)../;$(ProjectDir)../resip/stack;$(ProjectDir)../contrib/pcre;$(ProjectDir)../contrib/GeoIP/libGeoIP;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ <AdditionalIncludeDirectories>$(ProjectDir)../;$(ProjectDir)../resip/stack;$(ProjectDir)../contrib/pcre;$(ProjectDir)../contrib/GeoIP/libGeoIP;$(ProjectDir)../contrib/db/build_windows;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>WIN32;_DEBUG;USE_ARES;USE_IPV6;USE_MAXMIND_GEOIP;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<MinimalRebuild>false</MinimalRebuild>
<BasicRuntimeChecks>
@@ -194,7 +194,7 @@
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<ClCompile>
- <AdditionalIncludeDirectories>$(ProjectDir)../;$(ProjectDir)../resip/stack;$(ProjectDir)../contrib/pcre;$(ProjectDir)../contrib/GeoIP/libGeoIP;$(ProjectDir)../contrib/MySQLConnectorC/include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ <AdditionalIncludeDirectories>$(ProjectDir)../;$(ProjectDir)../resip/stack;$(ProjectDir)../contrib/pcre;$(ProjectDir)../contrib/GeoIP/libGeoIP;$(ProjectDir)../contrib/MySQLConnectorC/include;$(ProjectDir)../contrib/db/build_windows;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>WIN32;NDEBUG;USE_ARES;USE_IPV6;USE_MYSQL;USE_MAXMIND_GEOIP;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<MinimalRebuild>false</MinimalRebuild>
<RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
@@ -207,7 +207,7 @@
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<ClCompile>
- <AdditionalIncludeDirectories>$(ProjectDir)../;$(ProjectDir)../resip/stack;$(ProjectDir)../contrib/pcre;$(ProjectDir)../contrib/GeoIP/libGeoIP;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ <AdditionalIncludeDirectories>$(ProjectDir)../;$(ProjectDir)../resip/stack;$(ProjectDir)../contrib/pcre;$(ProjectDir)../contrib/GeoIP/libGeoIP;$(ProjectDir)../contrib/db/build_windows;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>WIN32;NDEBUG;USE_ARES;USE_IPV6;USE_MAXMIND_GEOIP;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<MinimalRebuild>false</MinimalRebuild>
<RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
@@ -221,7 +221,7 @@
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='SSL-Debug|Win32'">
<ClCompile>
<Optimization>Disabled</Optimization>
- <AdditionalIncludeDirectories>$(ProjectDir)../;$(ProjectDir)../resip/stack;$(ProjectDir)../contrib/pcre;$(ProjectDir)../contrib/openssl/include;$(ProjectDir)../contrib/openssl/inc32;$(ProjectDir)../contrib/GeoIP/libGeoIP;$(ProjectDir)../contrib/MySQLConnectorC/include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ <AdditionalIncludeDirectories>$(ProjectDir)../;$(ProjectDir)../resip/stack;$(ProjectDir)../contrib/pcre;$(ProjectDir)../contrib/openssl/include;$(ProjectDir)../contrib/openssl/inc32;$(ProjectDir)../contrib/GeoIP/libGeoIP;$(ProjectDir)../contrib/MySQLConnectorC/include;$(ProjectDir)../contrib/db/build_windows;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>WIN32;_DEBUG;USE_ARES;LEAK_CHECK;USE_IPV6;USE_MYSQL;USE_SSL;USE_MAXMIND_GEOIP;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<MinimalRebuild>false</MinimalRebuild>
<BasicRuntimeChecks>
@@ -237,7 +237,7 @@
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='SSL-Debug|x64'">
<ClCompile>
<Optimization>Disabled</Optimization>
- <AdditionalIncludeDirectories>$(ProjectDir)../;$(ProjectDir)../resip/stack;$(ProjectDir)../contrib/pcre;$(ProjectDir)../contrib/openssl/include;$(ProjectDir)../contrib/openssl/inc32;$(ProjectDir)../contrib/GeoIP/libGeoIP;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ <AdditionalIncludeDirectories>$(ProjectDir)../;$(ProjectDir)../resip/stack;$(ProjectDir)../contrib/pcre;$(ProjectDir)../contrib/openssl/include;$(ProjectDir)../contrib/openssl/inc32;$(ProjectDir)../contrib/GeoIP/libGeoIP;$(ProjectDir)../contrib/db/build_windows;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>WIN32;_DEBUG;USE_ARES;LEAK_CHECK;USE_IPV6;USE_SSL;USE_MAXMIND_GEOIP;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<MinimalRebuild>false</MinimalRebuild>
<BasicRuntimeChecks>
@@ -252,7 +252,7 @@
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='SSL-Release|Win32'">
<ClCompile>
- <AdditionalIncludeDirectories>$(ProjectDir)../;$(ProjectDir)../resip/stack;$(ProjectDir)../contrib/pcre;$(ProjectDir)../contrib/openssl/include;$(ProjectDir)../contrib/openssl/inc32;$(ProjectDir)../contrib/GeoIP/libGeoIP;$(ProjectDir)../contrib/MySQLConnectorC/include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ <AdditionalIncludeDirectories>$(ProjectDir)../;$(ProjectDir)../resip/stack;$(ProjectDir)../contrib/pcre;$(ProjectDir)../contrib/openssl/include;$(ProjectDir)../contrib/openssl/inc32;$(ProjectDir)../contrib/GeoIP/libGeoIP;$(ProjectDir)../contrib/MySQLConnectorC/include;$(ProjectDir)../contrib/db/build_windows;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>WIN32;NDEBUG;USE_ARES;USE_IPV6;USE_SSL;USE_MYSQL;USE_MAXMIND_GEOIP;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<MinimalRebuild>false</MinimalRebuild>
<RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
@@ -265,7 +265,7 @@
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='SSL-Release|x64'">
<ClCompile>
- <AdditionalIncludeDirectories>$(ProjectDir)../;$(ProjectDir)../resip/stack;$(ProjectDir)../contrib/pcre;$(ProjectDir)../contrib/openssl/include;$(ProjectDir)../contrib/openssl/inc32;$(ProjectDir)../contrib/GeoIP/libGeoIP;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ <AdditionalIncludeDirectories>$(ProjectDir)../;$(ProjectDir)../resip/stack;$(ProjectDir)../contrib/pcre;$(ProjectDir)../contrib/openssl/include;$(ProjectDir)../contrib/openssl/inc32;$(ProjectDir)../contrib/GeoIP/libGeoIP;$(ProjectDir)../contrib/db/build_windows;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>WIN32;NDEBUG;USE_ARES;USE_IPV6;USE_SSL;USE_MAXMIND_GEOIP;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<MinimalRebuild>false</MinimalRebuild>
<RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
@@ -292,6 +292,7 @@
</ItemGroup>
<ItemGroup>
<ClCompile Include="AbstractDb.cxx" />
+ <ClCompile Include="AccountingCollector.cxx" />
<ClCompile Include="AclStore.cxx" />
<ClCompile Include="FilterStore.cxx" />
<ClCompile Include="monkeys\AmIResponsible.cxx" />
@@ -299,6 +300,7 @@
<ClCompile Include="monkeys\GeoProximityTargetSorter.cxx" />
<ClCompile Include="monkeys\MessageSilo.cxx" />
<ClCompile Include="monkeys\RequestFilter.cxx" />
+ <ClCompile Include="PersistentMessageQueue.cxx" />
<ClCompile Include="ProxyConfig.cxx" />
<ClCompile Include="SiloStore.cxx" />
<ClCompile Include="stateAgents\CertPublicationHandler.cxx">
@@ -370,6 +372,7 @@
</ItemGroup>
<ItemGroup>
<ClInclude Include="AbstractDb.hxx" />
+ <ClInclude Include="AccountingCollector.hxx" />
<ClInclude Include="Ack200DoneMessage.hxx" />
<ClInclude Include="AclStore.hxx" />
<ClInclude Include="AsyncProcessor.hxx" />
@@ -382,6 +385,7 @@
<ClInclude Include="monkeys\GeoProximityTargetSorter.hxx" />
<ClInclude Include="monkeys\MessageSilo.hxx" />
<ClInclude Include="monkeys\RequestFilter.hxx" />
+ <ClInclude Include="PersistentMessageQueue.hxx" />
<ClInclude Include="ProxyConfig.hxx" />
<ClInclude Include="SiloStore.hxx" />
<ClInclude Include="stateAgents\CertPublicationHandler.hxx" />
@@ -426,6 +430,7 @@
<ClInclude Include="UserAuthGrabber.hxx" />
<ClInclude Include="UserInfoMessage.hxx" />
<ClInclude Include="UserStore.hxx" />
+ <ClInclude Include="Worker.hxx" />
<ClInclude Include="WorkerThread.hxx" />
<ClInclude Include="XmlRpcConnection.hxx" />
<ClInclude Include="XmlRpcServerBase.hxx" />
Index: repro/reprolib_10_0.vcxproj.filters
===================================================================
--- repro/reprolib_10_0.vcxproj.filters (.../branches/resiprocate-1.8) (revision 9855)
+++ repro/reprolib_10_0.vcxproj.filters (.../main) (revision 9855)
@@ -168,6 +168,12 @@
<ClCompile Include="monkeys\MessageSilo.cxx">
<Filter>Source Files</Filter>
</ClCompile>
+ <ClCompile Include="PersistentMessageQueue.cxx">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="AccountingCollector.cxx">
+ <Filter>Source Files</Filter>
+ </ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="AbstractDb.hxx">
@@ -350,5 +356,14 @@
<ClInclude Include="monkeys\MessageSilo.hxx">
<Filter>Header Files</Filter>
</ClInclude>
+ <ClInclude Include="PersistentMessageQueue.hxx">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="Worker.hxx">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="AccountingCollector.hxx">
+ <Filter>Header Files</Filter>
+ </ClInclude>
</ItemGroup>
</Project>
\ No newline at end of file
Index: repro/AccountingCollector.cxx
===================================================================
--- repro/AccountingCollector.cxx (.../branches/resiprocate-1.8) (revision 0)
+++ repro/AccountingCollector.cxx (.../main) (revision 9855)
@@ -0,0 +1,759 @@
+#if defined(HAVE_CONFIG_H)
+#include "config.h"
+#endif
+
+#include <iostream>
+
+// JSON library includes
+#include "rutil/cajun/json/reader.h"
+#include "rutil/cajun/json/writer.h"
+#include "rutil/cajun/json/elements.h"
+
+#include "repro/AccountingCollector.hxx"
+#include "repro/RequestContext.hxx"
+#include "repro/ProxyConfig.hxx"
+#include "repro/PersistentMessageQueue.hxx"
+#include "resip/stack/Tuple.hxx"
+#include "resip/stack/Helper.hxx"
+#include "resip/stack/SipMessage.hxx"
+#include "rutil/Logger.hxx"
+
+#include "rutil/WinLeakCheck.hxx"
+
+#define RESIPROCATE_SUBSYSTEM Subsystem::REPRO
+
+using namespace resip;
+using namespace repro;
+using namespace json;
+using namespace std;
+
+const static Data sessionEventQueueName = "sessioneventqueue";
+const static Data registrationEventQueueName = "regeventqueue";
+
+AccountingCollector::AccountingCollector(ProxyConfig& config) :
+ mDbBaseDir(config.getConfigData("DatabasePath", "./", true)),
+ mSessionEventQueue(0),
+ mRegistrationEventQueue(0),
+ mSessionAccountingAddRoutingHeaders(config.getConfigBool("SessionAccountingAddRoutingHeaders", false)),
+ mSessionAccountingAddViaHeaders(config.getConfigBool("SessionAccountingAddViaHeaders", false)),
+ mRegistrationAccountingAddRoutingHeaders(config.getConfigBool("RegistrationAccountingAddRoutingHeaders", false)),
+ mRegistrationAccountingAddViaHeaders(config.getConfigBool("RegistrationAccountingAddViaHeaders", false)),
+ mRegistrationAccountingLogRefreshes(config.getConfigBool("RegistrationAccountingLogRefreshes", false)),
+ mFifo(0, 0) // not limited by time or size
+{
+ if(config.getConfigBool("SessionAccountingEnabled", false))
+ {
+ if(!initializeEventQueue(SessionEventType))
+ {
+ ErrLog(<< "AccountingCollector: cannot initialize session event queue!");
+ }
+ }
+ if(config.getConfigBool("RegistrationAccountingEnabled", false))
+ {
+ if(!initializeEventQueue(RegistrationEventType))
+ {
+ ErrLog(<< "AccountingCollector: cannot initialize registration event queue!");
+ }
+ }
+
+ run(); // Start thread
+}
+
+AccountingCollector::~AccountingCollector()
+{
+ // Shutdown thread and wait for it to complete
+ shutdown();
+ join();
+
+ delete mSessionEventQueue;
+ delete mRegistrationEventQueue;
+}
+
+void
+AccountingCollector::doRegistrationAccounting(AccountingCollector::RegistrationEvent regevent, const resip::SipMessage& msg)
+{
+ assert(msg.isRequest());
+ assert(msg.method() == REGISTER);
+
+ if(regevent == RegistrationRefreshed && !mRegistrationAccountingLogRefreshes)
+ {
+ // if mRegistrationAccountingLogRefreshes is false then don't log refreshes
+ return;
+ }
+
+ DateCategory datetime;
+ if(!msg.exists(h_CallId) || !msg.header(h_CallId).isWellFormed())
+ {
+ ErrLog(<< "AccountingCollector::doRegistrationAccounting: missing proper callId header: " << msg);
+ return;
+ }
+ Object regEvent;
+ regEvent["EventId"] = Number(regevent);
+ switch(regevent)
+ {
+ case RegistrationAdded:
+ regEvent["EventName"] = String("Registration Added");
+ break;
+ case RegistrationRefreshed:
+ regEvent["EventName"] = String("Registration Refreshed");
+ break;
+ case RegistrationRemoved:
+ regEvent["EventName"] = String("Registration Removed");
+ break;
+ case RegistrationRemovedAll:
+ regEvent["EventName"] = String("Registration Removed All");
+ break;
+ }
+ regEvent["Datetime"] = String(Data::from(datetime).c_str());
+ regEvent["CallId"] = String(msg.header(h_CallId).value().c_str());
+ if(msg.exists(h_To) && msg.header(h_To).isWellFormed())
+ {
+ if(!msg.header(h_To).displayName().empty())
+ {
+ regEvent["User"]["DisplayName"] = String(msg.header(h_To).displayName().c_str());
+ }
+ regEvent["User"]["Aor"] = String(Data::from(msg.header(h_To).uri().getAorAsUri(msg.getSource().getType())).c_str());
+ }
+ if(msg.exists(h_From) && msg.header(h_From).isWellFormed())
+ {
+ if(msg.header(h_From).uri() != msg.header(h_To).uri()) // Only log from is different from To
+ {
+ if(!msg.header(h_From).displayName().empty())
+ {
+ regEvent["From"]["DisplayName"] = String(msg.header(h_From).displayName().c_str());
+ }
+ regEvent["From"]["Uri"] = String(Data::from(msg.header(h_From).uri()).c_str());
+ }
+ }
+ if(msg.exists(h_Contacts) && !msg.header(h_Contacts).empty())
+ {
+ Array arrayContacts;
+ NameAddrs::const_iterator contactIt = msg.header(h_Contacts).begin();
+ for(; contactIt != msg.header(h_Contacts).end(); contactIt++)
+ {
+ if(contactIt->isWellFormed())
+ {
+ arrayContacts.Insert(String(Data::from(*contactIt).c_str()));
+ }
+ }
+ if(!arrayContacts.Empty())
+ {
+ regEvent["Contacts"] = arrayContacts;
+ }
+ }
+ if(msg.exists(h_Expires) && msg.header(h_Expires).isWellFormed())
+ {
+ regEvent["Expires"] = Number(msg.header(h_Expires).value());
+ }
+ if(mRegistrationAccountingAddViaHeaders &&
+ msg.exists(h_Vias) && !msg.header(h_Vias).empty())
+ {
+ Array arrayVias;
+ Vias::const_iterator viaIt = msg.header(h_Vias).begin();
+ for(; viaIt != msg.header(h_Vias).end(); viaIt++)
+ {
+ if(viaIt->isWellFormed())
+ {
+ arrayVias.Insert(String(Data::from(*viaIt).c_str()));
+ }
+ }
+ if(!arrayVias.Empty())
+ {
+ regEvent["Vias"] = arrayVias;
+ }
+ }
+ Tuple publicAddress = Helper::getClientPublicAddress(msg);
+ if(publicAddress.getType() != UNKNOWN_TRANSPORT)
+ {
+ regEvent["ClientPublicAddress"]["Transport"] = String(Tuple::toData(publicAddress.getType()).c_str());
+ regEvent["ClientPublicAddress"]["IP"] = String(Tuple::inet_ntop(publicAddress).c_str());
+ regEvent["ClientPublicAddress"]["Port"] = Number(publicAddress.getPort());
+ }
+ if(mRegistrationAccountingAddRoutingHeaders &&
+ msg.exists(h_Routes) && !msg.header(h_Routes).empty())
+ {
+ Array arrayRoutes;
+ NameAddrs::const_iterator routeIt = msg.header(h_Routes).begin();
+ for(; routeIt != msg.header(h_Routes).end(); routeIt++)
+ {
+ if(routeIt->isWellFormed())
+ {
+ arrayRoutes.Insert(String(Data::from(*routeIt).c_str()));
+ }
+ }
+ if(!arrayRoutes.Empty())
+ {
+ regEvent["Routes"] = arrayRoutes;
+ }
+ }
+ if(mRegistrationAccountingAddRoutingHeaders &&
+ msg.exists(h_Paths) && !msg.header(h_Paths).empty())
+ {
+ Array arrayPaths;
+ NameAddrs::const_iterator pathIt = msg.header(h_Paths).begin();
+ for(; pathIt != msg.header(h_Paths).end(); pathIt++)
+ {
+ if(pathIt->isWellFormed())
+ {
+ arrayPaths.Insert(String(Data::from(*pathIt).c_str()));
+ }
+ }
+ if(!arrayPaths.Empty())
+ {
+ regEvent["Paths"] = arrayPaths;
+ }
+ }
+ if(msg.exists(h_UserAgent) && msg.header(h_UserAgent).isWellFormed())
+ {
+ regEvent["UserAgent"] = String(msg.header(h_UserAgent).value().c_str());
+ }
+ pushEventObjectToQueue(regEvent, RegistrationEventType);
+}
+
+void
+AccountingCollector::doSessionAccounting(const resip::SipMessage& msg, bool received, RequestContext& context)
+{
+ //DebugLog(<< "AccountingCollector::doSessionAccounting: " << msg.brief());
+ if(msg.isRequest())
+ {
+ if(msg.method() == INVITE && !msg.header(h_To).exists(p_tag))
+ {
+ // Dialog creating INVITE
+ if(received)
+ {
+ // This came from the wire - so it is new session
+ DateCategory datetime;
+ if(!msg.exists(h_CallId) || !msg.header(h_CallId).isWellFormed())
+ {
+ ErrLog(<< "AccountingCollector::doSessionAccounting: missing proper callId header: " << msg);
+ return;
+ }
+ Object sessionEvent;
+ sessionEvent["EventId"] = Number(SessionCreated);
+ sessionEvent["EventName"] = String("Session Created");
+ sessionEvent["Datetime"] = String(Data::from(datetime).c_str());
+ sessionEvent["CallId"] = String(msg.header(h_CallId).value().c_str());
+ sessionEvent["RequestUri"] = String(Data::from(msg.header(h_RequestLine).uri()).c_str());
+ if(msg.exists(h_To) && msg.header(h_To).isWellFormed())
+ {
+ if(!msg.header(h_To).displayName().empty())
+ {
+ sessionEvent["To"]["DisplayName"] = String(msg.header(h_To).displayName().c_str());
+ }
+ sessionEvent["To"]["Uri"] = String(Data::from(msg.header(h_To).uri()).c_str());
+ }
+ if(msg.exists(h_From) && msg.header(h_From).isWellFormed())
+ {
+ if(!msg.header(h_From).displayName().empty())
+ {
+ sessionEvent["From"]["DisplayName"] = String(msg.header(h_From).displayName().c_str());
+ }
+ sessionEvent["From"]["Uri"] = String(Data::from(msg.header(h_From).uri()).c_str());
+ }
+ if(msg.exists(h_Contacts) && !msg.header(h_Contacts).empty() && msg.header(h_Contacts).front().isWellFormed())
+ {
+ sessionEvent["Contact"] = String(Data::from(msg.header(h_Contacts).front()).c_str());
+ }
+ if(mSessionAccountingAddViaHeaders &&
+ msg.exists(h_Vias) && !msg.header(h_Vias).empty())
+ {
+ Array arrayVias;
+ Vias::const_iterator viaIt = msg.header(h_Vias).begin();
+ for(; viaIt != msg.header(h_Vias).end(); viaIt++)
+ {
+ if(viaIt->isWellFormed())
+ {
+ arrayVias.Insert(String(Data::from(*viaIt).c_str()));
+ }
+ }
+ if(!arrayVias.Empty())
+ {
+ sessionEvent["Vias"] = arrayVias;
+ }
+ }
+ Tuple publicAddress = Helper::getClientPublicAddress(msg);
+ if(publicAddress.getType() != UNKNOWN_TRANSPORT)
+ {
+ sessionEvent["ClientPublicAddress"]["Transport"] = String(Tuple::toData(publicAddress.getType()).c_str());
+ sessionEvent["ClientPublicAddress"]["IP"] = String(Tuple::inet_ntop(publicAddress).c_str());
+ sessionEvent["ClientPublicAddress"]["Port"] = Number(publicAddress.getPort());
+ }
+ if(mSessionAccountingAddRoutingHeaders &&
+ msg.exists(h_Routes) && !msg.header(h_Routes).empty())
+ {
+ Array arrayRoutes;
+ NameAddrs::const_iterator routeIt = msg.header(h_Routes).begin();
+ for(; routeIt != msg.header(h_Routes).end(); routeIt++)
+ {
+ if(routeIt->isWellFormed())
+ {
+ arrayRoutes.Insert(String(Data::from(*routeIt).c_str()));
+ }
+ }
+ if(!arrayRoutes.Empty())
+ {
+ sessionEvent["Routes"] = arrayRoutes;
+ }
+ }
+ if(mSessionAccountingAddRoutingHeaders &&
+ msg.exists(h_RecordRoutes) && !msg.header(h_RecordRoutes).empty())
+ {
+ Array arrayRecordRoutes;
+ NameAddrs::const_iterator recordRouteIt = msg.header(h_RecordRoutes).begin();
+ for(; recordRouteIt != msg.header(h_RecordRoutes).end(); recordRouteIt++)
+ {
+ if(recordRouteIt->isWellFormed())
+ {
+ arrayRecordRoutes.Insert(String(Data::from(*recordRouteIt).c_str()));
+ }
+ }
+ if(!arrayRecordRoutes.Empty())
+ {
+ sessionEvent["RecordRoutes"] = arrayRecordRoutes;
+ }
+ }
+ if(msg.exists(h_UserAgent) && msg.header(h_UserAgent).isWellFormed())
+ {
+ sessionEvent["UserAgent"] = String(msg.header(h_UserAgent).value().c_str());
+ }
+ context.setSessionCreatedEventSent();
+ pushEventObjectToQueue(sessionEvent, SessionEventType);
+ }
+ else
+ {
+ // This is being forwarded to a target
+ DateCategory datetime;
+ if(!msg.exists(h_CallId) || !msg.header(h_CallId).isWellFormed())
+ {
+ ErrLog(<< "AccountingCollector::doSessionAccounting: missing proper callId header: " << msg);
+ return;
+ }
+ Object sessionEvent;
+ sessionEvent["EventId"] = Number(SessionRouted);
+ sessionEvent["EventName"] = String("Session Routed");
+ sessionEvent["Datetime"] = String(Data::from(datetime).c_str());
+ sessionEvent["CallId"] = String(msg.header(h_CallId).value().c_str());
+ sessionEvent["TargetUri"] = String(Data::from(msg.header(h_RequestLine).uri()).c_str());
+ if(mSessionAccountingAddRoutingHeaders &&
+ msg.exists(h_Routes) && !msg.header(h_Routes).empty())
+ {
+ Array arrayRoutes;
+ NameAddrs::const_iterator routeIt = msg.header(h_Routes).begin();
+ for(; routeIt != msg.header(h_Routes).end(); routeIt++)
+ {
+ if(routeIt->isWellFormed())
+ {
+ arrayRoutes.Insert(String(Data::from(*routeIt).c_str()));
+ }
+ }
+ if(!arrayRoutes.Empty())
+ {
+ sessionEvent["Routes"] = arrayRoutes;
+ }
+ }
+ pushEventObjectToQueue(sessionEvent, SessionEventType);
+ }
+ }
+ else if(msg.method() == BYE && received)
+ {
+ // Session Ended
+ DateCategory datetime;
+ if(!msg.exists(h_CallId) || !msg.header(h_CallId).isWellFormed())
+ {
+ ErrLog(<< "AccountingCollector::doSessionAccounting: missing proper callId header: " << msg);
+ return;
+ }
+ Object sessionEvent;
+ sessionEvent["EventId"] = Number(SessionEnded);
+ sessionEvent["EventName"] = String("Session Ended");
+ sessionEvent["Datetime"] = String(Data::from(datetime).c_str());
+ sessionEvent["CallId"] = String(msg.header(h_CallId).value().c_str());
+ if(msg.exists(h_From) && msg.header(h_From).isWellFormed())
+ {
+ if(!msg.header(h_From).displayName().empty())
+ {
+ sessionEvent["From"]["DisplayName"] = String(msg.header(h_From).displayName().c_str());
+ }
+ sessionEvent["From"]["Uri"] = String(Data::from(msg.header(h_From).uri()).c_str());
+ }
+ if(msg.exists(h_Reasons) && !msg.header(h_Reasons).empty() && msg.header(h_Reasons).front().isWellFormed())
+ {
+ // Just look at first occurance
+ sessionEvent["Reason"]["Value"] = String(msg.header(h_Reasons).front().value().c_str());
+ if(msg.header(h_Reasons).front().exists(p_cause))
+ {
+ sessionEvent["Reason"]["Cause"] = Number(msg.header(h_Reasons).front().param(p_cause));
+ }
+ if(msg.header(h_Reasons).front().exists(p_text) && !msg.header(h_Reasons).front().param(p_text).empty())
+ {
+ sessionEvent["Reason"]["Text"] = String(msg.header(h_Reasons).front().param(p_text).c_str());
+ }
+ }
+ pushEventObjectToQueue(sessionEvent, SessionEventType);
+ }
+ else if(msg.method() == CANCEL && received)
+ {
+ // Session Cancelled
+ DateCategory datetime;
+ if(!msg.exists(h_CallId) || !msg.header(h_CallId).isWellFormed())
+ {
+ ErrLog(<< "AccountingCollector::doSessionAccounting: missing proper callId header: " << msg);
+ return;
+ }
+ Object sessionEvent;
+ sessionEvent["EventId"] = Number(SessionCancelled);
+ sessionEvent["EventName"] = String("Session Cancelled");
+ sessionEvent["Datetime"] = String(Data::from(datetime).c_str());
+ sessionEvent["CallId"] = String(msg.header(h_CallId).value().c_str());
+ if(msg.exists(h_Reasons) && !msg.header(h_Reasons).empty() && msg.header(h_Reasons).front().isWellFormed())
+ {
+ // Just look at first occurance
+ sessionEvent["Reason"]["Value"] = String(msg.header(h_Reasons).front().value().c_str());
+ if(msg.header(h_Reasons).front().exists(p_cause))
+ {
+ sessionEvent["Reason"]["Cause"] = Number(msg.header(h_Reasons).front().param(p_cause));
+ }
+ if(msg.header(h_Reasons).front().exists(p_text) && !msg.header(h_Reasons).front().param(p_text).empty())
+ {
+ sessionEvent["Reason"]["Text"] = String(msg.header(h_Reasons).front().param(p_text).c_str());
+ }
+ }
+ pushEventObjectToQueue(sessionEvent, SessionEventType);
+ }
+ else if(msg.method() == REFER && received && msg.header(h_To).exists(p_tag))
+ {
+ // Only handle mid-dialog REFERs for now
+ // Session Redirected
+ DateCategory datetime;
+ if(!msg.exists(h_CallId) || !msg.header(h_CallId).isWellFormed())
+ {
+ ErrLog(<< "AccountingCollector::doSessionAccounting: missing proper callId header: " << msg);
+ return;
+ }
+ Object sessionEvent;
+ sessionEvent["EventId"] = Number(SessionRedirected);
+ sessionEvent["EventName"] = String("Session Redirected");
+ sessionEvent["Datetime"] = String(Data::from(datetime).c_str());
+ sessionEvent["CallId"] = String(msg.header(h_CallId).value().c_str());
+ if(msg.exists(h_From) && msg.header(h_From).isWellFormed())
+ {
+ if(!msg.header(h_From).displayName().empty())
+ {
+ sessionEvent["ReferredBy"]["DisplayName"] = String(msg.header(h_From).displayName().c_str());
+ }
+ sessionEvent["ReferredBy"]["Uri"] = String(Data::from(msg.header(h_From).uri()).c_str());
+ }
+ if(msg.exists(h_ReferTo) && msg.header(h_ReferTo).isWellFormed())
+ {
+ sessionEvent["TargetUri"] = String(Data::from(msg.header(h_ReferTo).uri()).c_str());
+ }
+ pushEventObjectToQueue(sessionEvent, SessionEventType);
+ }
+ }
+ // Response
+ else
+ {
+ if(!received && msg.method() == INVITE)
+ {
+ if(msg.header(h_StatusLine).statusCode() >= 200 &&
+ msg.header(h_StatusLine).statusCode() < 300)
+ {
+ // Session Answered
+ DateCategory datetime;
+ if(!msg.exists(h_CallId) || !msg.header(h_CallId).isWellFormed())
+ {
+ ErrLog(<< "AccountingCollector::doSessionAccounting: missing proper callId header: " << msg);
+ return;
+ }
+ Object sessionEvent;
+ sessionEvent["EventId"] = Number(SessionEstablished);
+ sessionEvent["EventName"] = String("Session Established");
+ sessionEvent["Datetime"] = String(Data::from(datetime).c_str());
+ sessionEvent["CallId"] = String(msg.header(h_CallId).value().c_str());
+ if(msg.exists(h_Contacts) && !msg.header(h_Contacts).empty() && msg.header(h_Contacts).front().isWellFormed())
+ {
+ sessionEvent["Contact"] = String(Data::from(msg.header(h_Contacts).front()).c_str());
+ }
+ if(mSessionAccountingAddRoutingHeaders &&
+ msg.exists(h_RecordRoutes) && !msg.header(h_RecordRoutes).empty())
+ {
+ Array arrayRecordRoutes;
+ NameAddrs::const_iterator recordRouteIt = msg.header(h_RecordRoutes).begin();
+ for(; recordRouteIt != msg.header(h_RecordRoutes).end(); recordRouteIt++)
+ {
+ if(recordRouteIt->isWellFormed())
+ {
+ arrayRecordRoutes.Insert(String(Data::from(*recordRouteIt).c_str()));
+ }
+ }
+ if(!arrayRecordRoutes.Empty())
+ {
+ sessionEvent["RecordRoutes"] = arrayRecordRoutes;
+ }
+ }
+ if(msg.exists(h_UserAgent) && msg.header(h_UserAgent).isWellFormed())
+ {
+ sessionEvent["UserAgent"] = String(msg.header(h_UserAgent).value().c_str());
+ }
+ context.setSessionEstablishedEventSent();
+ pushEventObjectToQueue(sessionEvent, SessionEventType);
+ }
+ else if(msg.header(h_StatusLine).statusCode() >= 300 &&
+ msg.header(h_StatusLine).statusCode() < 400)
+ {
+ // Session Redirected
+ // Session Answered
+ DateCategory datetime;
+ if(!msg.exists(h_CallId) || !msg.header(h_CallId).isWellFormed())
+ {
+ ErrLog(<< "AccountingCollector::doSessionAccounting: missing proper callId header: " << msg);
+ return;
+ }
+ Object sessionEvent;
+ sessionEvent["EventId"] = Number(SessionRedirected);
+ sessionEvent["EventName"] = String("Session Redirected");
+ sessionEvent["Datetime"] = String(Data::from(datetime).c_str());
+ sessionEvent["CallId"] = String(msg.header(h_CallId).value().c_str());
+ if(msg.exists(h_Contacts) && !msg.header(h_Contacts).empty())
+ {
+ Array arrayContacts;
+ NameAddrs::const_iterator contactIt = msg.header(h_Contacts).begin();
+ for(; contactIt != msg.header(h_Contacts).end(); contactIt++)
+ {
+ if(contactIt->isWellFormed())
+ {
+ arrayContacts.Insert(String(Data::from(*contactIt).c_str()));
+ }
+ }
+ if(!arrayContacts.Empty())
+ {
+ sessionEvent["TargetUris"] = arrayContacts;
+ }
+ }
+ if(msg.exists(h_UserAgent) && msg.header(h_UserAgent).isWellFormed())
+ {
+ sessionEvent["UserAgent"] = String(msg.header(h_UserAgent).value().c_str());
+ }
+ pushEventObjectToQueue(sessionEvent, SessionEventType);
+ }
+ else if(msg.header(h_StatusLine).statusCode() >= 400 &&
+ msg.header(h_StatusLine).statusCode() < 700)
+ {
+ // Session Error
+ Object sessionEvent;
+ // Session Answered
+ DateCategory datetime;
+ if(!msg.exists(h_CallId) || !msg.header(h_CallId).isWellFormed())
+ {
+ ErrLog(<< "AccountingCollector::doSessionAccounting: missing proper callId header: " << msg);
+ return;
+ }
+ sessionEvent["EventId"] = Number(SessionError);
+ sessionEvent["EventName"] = String("Session Error");
+ sessionEvent["Datetime"] = String(Data::from(datetime).c_str());
+ sessionEvent["CallId"] = String(msg.header(h_CallId).value().c_str());
+ sessionEvent["Status"]["Code"] = Number(msg.header(h_StatusLine).statusCode());
+ if(!msg.header(h_StatusLine).reason().empty())
+ {
+ sessionEvent["Status"]["Text"] = String(msg.header(h_StatusLine).reason().c_str());
+ }
+ if(msg.exists(h_Warnings) && !msg.header(h_Warnings).empty() && msg.header(h_Warnings).front().isWellFormed())
+ {
+ // Just look at first occurance
+ sessionEvent["Warning"]["Code"] = Number(msg.header(h_Warnings).front().code());
+ if(!msg.header(h_Warnings).front().text().empty())
+ {
+ sessionEvent["Warning"]["Text"] = String(msg.header(h_Warnings).front().text().c_str());
+ }
+ }
+ // Note: a reason header is not usually present on a response - but we will use one if it is
+ if(msg.exists(h_Reasons) && !msg.header(h_Reasons).empty() && msg.header(h_Reasons).front().isWellFormed())
+ {
+ // Just look at first occurance
+ sessionEvent["Reason"]["Value"] = String(msg.header(h_Reasons).front().value().c_str());
+ if(msg.header(h_Reasons).front().exists(p_cause))
+ {
+ sessionEvent["Reason"]["Cause"] = Number(msg.header(h_Reasons).front().param(p_cause));
+ }
+ if(msg.header(h_Reasons).front().exists(p_text) && !msg.header(h_Reasons).front().param(p_text).empty())
+ {
+ sessionEvent["Reason"]["Text"] = String(msg.header(h_Reasons).front().param(p_text).c_str());
+ }
+ }
+ if(msg.exists(h_UserAgent) && msg.header(h_UserAgent).isWellFormed())
+ {
+ sessionEvent["UserAgent"] = String(msg.header(h_UserAgent).value().c_str());
+ }
+ pushEventObjectToQueue(sessionEvent, SessionEventType);
+ }
+ }
+ }
+}
+
+PersistentMessageEnqueue*
+AccountingCollector::initializeEventQueue(FifoEventType type, bool destroyFirst)
+{
+ switch(type)
+ {
+ case SessionEventType:
+ if(destroyFirst)
+ {
+ delete mSessionEventQueue;
+ mSessionEventQueue = 0;
+ }
+ if(!mSessionEventQueue)
+ {
+ mSessionEventQueue = new PersistentMessageEnqueue(mDbBaseDir);
+ if(!mSessionEventQueue->init(true, sessionEventQueueName))
+ {
+ delete mSessionEventQueue;
+ mSessionEventQueue = 0;
+ }
+ }
+ return mSessionEventQueue;
+ case RegistrationEventType:
+ if(destroyFirst)
+ {
+ delete mRegistrationEventQueue;
+ mRegistrationEventQueue = 0;
+ }
+ if(!mRegistrationEventQueue)
+ {
+ mRegistrationEventQueue = new PersistentMessageEnqueue(mDbBaseDir);
+ if(!mRegistrationEventQueue->init(true, registrationEventQueueName))
+ {
+ delete mRegistrationEventQueue;
+ mRegistrationEventQueue = 0;
+ }
+ }
+ return mRegistrationEventQueue;
+ default:
+ assert(false);
+ break;
+ }
+ return 0;
+}
+
+void
+AccountingCollector::pushEventObjectToQueue(Object& eventObject, AccountingCollector::FifoEventType type)
+{
+ FifoEvent* eventData = new FifoEvent;
+ eventData->mType = type;
+ {
+ DataStream ds(eventData->mData);
+ Writer::Write(eventObject, ds);
+ }
+
+ // Note: BerkeleyDb calls can block (ie. deaklock after consumer crash), so we use a
+ // Fifo and thread to ensure we don't block the core proxy processing
+ mFifo.add(eventData, TimeLimitFifo<FifoEvent>::InternalElement);
+}
+
+void
+AccountingCollector::internalProcess(std::auto_ptr<FifoEvent> eventData)
+{
+ InfoLog(<< "AccountingCollector::internalProcess: JSON=" << endl << eventData->mData);
+
+ PersistentMessageEnqueue* queue = initializeEventQueue(eventData->mType);
+
+ if(!queue)
+ {
+ ErrLog(<< "AccountingCollector: cannot initialize PersistentMessageQueue - dropping event!");
+ return;
+ }
+
+ if(!queue->push(eventData->mData))
+ {
+ // Error pushing - see if db recovery is needed
+ if(queue->isRecoveryNeeded())
+ {
+ if((queue = initializeEventQueue(eventData->mType, true /* destoryFirst */)) == 0)
+ {
+ ErrLog(<< "AccountingCollector: cannot initialize PersistentMessageQueue - dropping event!");
+ return;
+ }
+ else
+ {
+ if(!queue->push(eventData->mData))
+ {
+ ErrLog(<< "AccountingCollector: error pushing event to queue - dropping event!");
+ }
+ }
+ }
+ else
+ {
+ ErrLog(<< "AccountingCollector: error pushing event to queue - dropping event!");
+ }
+ }
+}
+
+void
+AccountingCollector::thread()
+{
+ while (!isShutdown() || !mFifo.empty()) // Ensure we drain the queue before shutting down
+ {
+ try
+ {
+ std::auto_ptr<FifoEvent> eventData(mFifo.getNext(1000)); // Only need to wake up to see if we are shutdown
+ if (eventData.get())
+ {
+ internalProcess(eventData);
+ }
+ }
+ catch (BaseException& e)
+ {
+ WarningLog (<< "Unhandled exception: " << e);
+ }
+ }
+}
+
+
+/* ====================================================================
+ * The Vovida Software License, Version 1.0
+ *
+ * Copyright (c) 2000 Vovida Networks, Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * 3. The names "VOCAL", "Vovida Open Communication Application Library",
+ * and "Vovida Open Communication Application Library (VOCAL)" must
+ * not be used to endorse or promote products derived from this
+ * software without prior written permission. For written
+ * permission, please contact vocal@xxxxxxxxxx.
+ *
+ * 4. Products derived from this software may not be called "VOCAL", nor
+ * may "VOCAL" appear in their name, without prior written
+ * permission of Vovida Networks, Inc.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESSED OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, TITLE AND
+ * NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT SHALL VOVIDA
+ * NETWORKS, INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT DAMAGES
+ * IN EXCESS OF $1,000, NOR FOR ANY INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
+ * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by Vovida
+ * Networks, Inc. and many individuals on behalf of Vovida Networks,
+ * Inc. For more information on Vovida Networks, Inc., please see
+ * <http://www.vovida.org/>.
+ *
+ */
Property changes on: repro/AccountingCollector.cxx
___________________________________________________________________
Added: svn:eol-style
+ native
Index: repro/Registrar.hxx
===================================================================
--- repro/Registrar.hxx (.../branches/resiprocate-1.8) (revision 9855)
+++ repro/Registrar.hxx (.../main) (revision 9855)
@@ -8,6 +8,7 @@
namespace repro
{
+class Proxy;
class RegistrarHandler
{
@@ -42,6 +43,8 @@
Registrar();
virtual ~Registrar();
+ void setProxy(Proxy* proxy) { mProxy = proxy; }
+
virtual void addRegistrarHandler(RegistrarHandler* handler);
virtual void onRefresh(resip::ServerRegistrationHandle, const resip::SipMessage& reg);
@@ -52,6 +55,7 @@
private:
std::list<RegistrarHandler*> mRegistrarHandlers;
+ Proxy* mProxy;
};
}
#endif
Index: repro/reprocmd/reprocmd.cpp
===================================================================
--- repro/reprocmd/reprocmd.cpp (.../branches/resiprocate-1.8) (revision 9855)
+++ repro/reprocmd/reprocmd.cpp (.../main) (revision 9855)
@@ -1,6 +1,3 @@
-// testXmlRpc.cpp : Defines the entry point for the console application.
-//
-
#include <rutil/DnsUtil.hxx>
#include <rutil/BaseException.hxx>
#include <rutil/XMLCursor.hxx>
@@ -44,7 +41,8 @@
cerr << " [fifoDescription=<desc>] - sets congestion tolerances" << endl;
cerr << " Shutdown - signal the proxy to shut down." << endl;
cerr << " Restart - signal the proxy to restart - leaving active registrations in place." << endl;
- cerr << " GetProxyConfig - retrieves the all of configuration being used by the proxy" << endl;
+ cerr << " GetProxyConfig - retrieves the all of configuration file settings currently" << endl;
+ cerr << " being used by the proxy" << endl;
exit(1);
}
@@ -214,3 +212,58 @@
}
}
}
+
+
+/* ====================================================================
+ * The Vovida Software License, Version 1.0
+ *
+ * Copyright (c) 2000-2012
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * 3. The names "VOCAL", "Vovida Open Communication Application Library",
+ * and "Vovida Open Communication Application Library (VOCAL)" must
+ * not be used to endorse or promote products derived from this
+ * software without prior written permission. For written
+ * permission, please contact vocal@xxxxxxxxxx.
+ *
+ * 4. Products derived from this software may not be called "VOCAL", nor
+ * may "VOCAL" appear in their name, without prior written
+ * permission of Vovida Networks, Inc.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESSED OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, TITLE AND
+ * NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT SHALL VOVIDA
+ * NETWORKS, INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT DAMAGES
+ * IN EXCESS OF $1,000, NOR FOR ANY INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
+ * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by Vovida
+ * Networks, Inc. and many individuals on behalf of Vovida Networks,
+ * Inc. For more information on Vovida Networks, Inc., please see
+ * <http://www.vovida.org/>.
+ *
+ */
+/*
+ * vi: set shiftwidth=3 expandtab:
+ */
+
Index: repro/PersistentMessageQueue.hxx
===================================================================
--- repro/PersistentMessageQueue.hxx (.../branches/resiprocate-1.8) (revision 0)
+++ repro/PersistentMessageQueue.hxx (.../main) (revision 9855)
@@ -0,0 +1,214 @@
+#if !defined(RESIP_PERSISTENTMESSAGEQUEUE_HXX)
+#define RESIP_PERSISTENTMESSAGEQUEUE_HXX
+
+#ifdef WIN32
+#include <db_cxx.h>
+#elif HAVE_CONFIG_H
+#include "config.h"
+#include DB_HEADER
+//#elif defined(__APPLE__)
+//#include <db42/db_cxx.h>
+#else
+#include <db_cxx.h>
+#endif
+
+#include "rutil/Data.hxx"
+#include <vector>
+
+// This class implements a persistent message queue that utilizes a BerkeleyDb backing store.
+// Messages are persisted out to disk and can be consumed from another process using the
+// PeristentMessageDequeue class.
+//
+// If PersistentMessageEnqueue::push or
+// PersistentMessageDequeue::pop or
+// PersistentMessageDequeue::commit
+// even fail, then the isRecoveryNeeded should be called. If this returns true, then the
+// PersistentMessageQueue in use should be destroyed and a new one created in order to "recover"
+// the backing store.
+//
+// Warning: If autoCommit is not used on PersistentMessageDequeue::pop then there can only be 1
+// consumer.
+//
+// Producer example:
+// -----------------
+// PersistentMessageEnqueue* queue = new PersistentMessageEnqueue;
+// if(queue->init(true, "msgqueue"))
+// {
+// for(int i = 0; i < 1000; i++)
+// {
+// Data qstr("test string" + Data(i));
+// if(!queue->push(qstr))
+// {
+// if(queue->isRecoveryNeeded())
+// {
+// delete queue;
+// queue = new PersistentMessageEnqueue;
+// if(!queue->init(true, "msgqueue")) break;
+// if(queue->push(qstr))
+// {
+// cout << "Queued: " << qstr << endl;
+// }
+// else
+// {
+// cout << "Error queuing - exiting!" << endl;
+// break;
+// }
+// }
+// else
+// {
+// cout << "Error queuing - exiting!" << endl;
+// break;
+// }
+// }
+// else
+// {
+// cout << "Queued: " << qstr << endl;
+// }
+// }
+//}
+//delete queue;
+//
+//
+// Consumer example:
+// -----------------
+//PersistentMessageDequeue* queue = new PersistentMessageDequeue;
+//if(queue->init(true, "msgqueue"))
+//{
+// vector<resip::Data> recs;
+// while(true)
+// {
+// if(queue->pop(5, recs, false))
+// {
+// if(recs.size() > 0)
+// {
+// for(int i = 0; i < recs.size(); i++)
+// {
+// cout << "Popped(" << i << "): " << recs[i] << endl;
+// }
+// queue->commit();
+// }
+// else
+// {
+// cout << "No records to pop." << endl;
+// Sleep(1000);
+// //break;
+// }
+// }
+// else
+// {
+// if(queue->isRecoveryNeeded())
+// {
+// delete queue;
+// queue = new PersistentMessageDequeue;
+// if(!queue->init(true, "msgqueue")) break;
+// }
+// else
+// {
+// cout << "Error Dequeuing!" << endl;
+// break;
+// }
+// }
+// }
+//}
+//delete queue;
+
+
+namespace repro
+{
+class PersistentMessageQueue : public DbEnv
+{
+public:
+ PersistentMessageQueue(const resip::Data& baseDir);
+ virtual ~PersistentMessageQueue();
+
+ bool init(bool sync, const resip::Data& queueName);
+ bool isRecoveryNeeded();
+
+protected:
+ Db* mDb;
+ resip::Data mBaseDir;
+ bool mRecoveryNeeded;
+};
+
+class PersistentMessageEnqueue : public PersistentMessageQueue
+{
+public:
+ PersistentMessageEnqueue(const resip::Data& baseDir) :
+ PersistentMessageQueue(baseDir) {}
+ virtual ~PersistentMessageEnqueue() {}
+
+ // Note: this has a potential to block if the a consumer crashes and leaves a lock open on the database (deadlock)
+ // typically restarting the consumer will "recover" the "dead" lock and allow this call to unblock
+ bool push(const resip::Data& data);
+};
+
+class PersistentMessageDequeue : public PersistentMessageQueue
+{
+public:
+ PersistentMessageDequeue(const resip::Data& baseDir) :
+ PersistentMessageQueue(baseDir),
+ mNumRecords(0) {}
+ virtual ~PersistentMessageDequeue () {}
+
+ // returns true for success, false for failure - can return true and 0 records if none available
+ // Note: if autoCommit is used then it is safe to allow multiple consumers
+ bool pop(size_t numRecords, std::vector<resip::Data>& records, bool autoCommit);
+ bool commit();
+ void abort();
+
+private:
+ size_t mNumRecords;
+ };
+
+}
+#endif
+
+/* ====================================================================
+ * The Vovida Software License, Version 1.0
+ *
+ * Copyright (c) 2000 Vovida Networks, Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * 3. The names "VOCAL", "Vovida Open Communication Application Library",
+ * and "Vovida Open Communication Application Library (VOCAL)" must
+ * not be used to endorse or promote products derived from this
+ * software without prior written permission. For written
+ * permission, please contact vocal@xxxxxxxxxx.
+ *
+ * 4. Products derived from this software may not be called "VOCAL", nor
+ * may "VOCAL" appear in their name, without prior written
+ * permission of Vovida Networks, Inc.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESSED OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, TITLE AND
+ * NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT SHALL VOVIDA
+ * NETWORKS, INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT DAMAGES
+ * IN EXCESS OF $1,000, NOR FOR ANY INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
+ * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by Vovida
+ * Networks, Inc. and many individuals on behalf of Vovida Networks,
+ * Inc. For more information on Vovida Networks, Inc., please see
+ * <http://www.vovida.org/>.
+ *
+ */
Property changes on: repro/PersistentMessageQueue.hxx
___________________________________________________________________
Added: svn:eol-style
+ native
Index: repro/Proxy.hxx
===================================================================
--- repro/Proxy.hxx (.../branches/resiprocate-1.8) (revision 9855)
+++ repro/Proxy.hxx (.../main) (revision 9855)
@@ -8,6 +8,7 @@
#include "rutil/HashMap.hxx"
#include "rutil/ThreadIf.hxx"
#include "rutil/KeyValueStore.hxx"
+#include "repro/AccountingCollector.hxx"
#include "repro/RequestContext.hxx"
#include "repro/TimerCMessage.hxx"
#include "repro/ProxyConfig.hxx"
@@ -100,6 +101,9 @@
// Accessor for global extensible state storage for monkeys
resip::KeyValueStore& getKeyValueStore() { return mKeyValueStore; }
+ void doSessionAccounting(const resip::SipMessage& sip, bool received, RequestContext& context);
+ void doRegistrationAccounting(repro::AccountingCollector::RegistrationEvent regEvent, const resip::SipMessage& sip);
+
protected:
virtual const resip::Data& name() const;
@@ -132,6 +136,10 @@
OptionsHandler* mOptionsHandler;
std::auto_ptr<RequestContextFactory> mRequestContextFactory;
+ bool mSessionAccountingEnabled;
+ bool mRegistrationAccountingEnabled;
+ AccountingCollector* mAccountingCollector;
+
// disabled
Proxy();
};
Index: repro/accountingconsumers/queuetostream_10_0.vcxproj.filters
===================================================================
--- repro/accountingconsumers/queuetostream_10_0.vcxproj.filters (.../branches/resiprocate-1.8) (revision 0)
+++ repro/accountingconsumers/queuetostream_10_0.vcxproj.filters (.../main) (revision 9855)
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <ItemGroup>
+ <Filter Include="Source Files">
+ <UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
+ <Extensions>cpp;c;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
+ </Filter>
+ <Filter Include="Header Files">
+ <UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
+ <Extensions>h;hpp;hxx;hm;inl;inc;xsd</Extensions>
+ </Filter>
+ <Filter Include="Resource Files">
+ <UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
+ <Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx</Extensions>
+ </Filter>
+ </ItemGroup>
+ <ItemGroup>
+ <ClCompile Include="queuetostream.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ </ItemGroup>
+</Project>
\ No newline at end of file
Index: repro/accountingconsumers/queuetostream.cpp
===================================================================
--- repro/accountingconsumers/queuetostream.cpp (.../branches/resiprocate-1.8) (revision 0)
+++ repro/accountingconsumers/queuetostream.cpp (.../main) (revision 9855)
@@ -0,0 +1,160 @@
+#include <signal.h>
+
+#include "repro/PersistentMessageQueue.hxx"
+#include <rutil/Logger.hxx>
+#include <rutil/WinLeakCheck.hxx>
+
+using namespace resip;
+using namespace std;
+using namespace repro;
+
+static bool finished = false;
+
+static void
+signalHandler(int signo)
+{
+ std::cerr << "Shutting down" << endl;
+ finished = true;
+}
+
+void sleepSeconds(unsigned int seconds)
+{
+#ifdef WIN32
+ Sleep(seconds*1000);
+#else
+ sleep(seconds);
+#endif
+}
+
+int
+main (int argc, char** argv)
+{
+ // Install signal handlers
+#ifndef _WIN32
+ if ( signal( SIGPIPE, SIG_IGN) == SIG_ERR)
+ {
+ cerr << "Couldn't install signal handler for SIGPIPE" << endl;
+ exit(-1);
+ }
+#endif
+
+ if ( signal( SIGINT, signalHandler ) == SIG_ERR )
+ {
+ cerr << "Couldn't install signal handler for SIGINT" << endl;
+ exit( -1 );
+ }
+
+ if ( signal( SIGTERM, signalHandler ) == SIG_ERR )
+ {
+ cerr << "Couldn't install signal handler for SIGTERM" << endl;
+ exit( -1 );
+ }
+
+ // Log any resip logs to cerr, since session events are logged to cout
+ Log::initialize(Log::Cerr, Log::Info, "");
+
+ Data msgQueueName("sessioneventqueue");
+ if(argc >= 2)
+ {
+ msgQueueName = argv[1];
+ }
+ PersistentMessageDequeue* queue = new PersistentMessageDequeue("");
+ if(queue->init(true, msgQueueName))
+ {
+ vector<resip::Data> recs;
+ while(!finished)
+ {
+ if(queue->pop(5, recs, true))
+ {
+ if(recs.size() > 0)
+ {
+ for(size_t i = 0; i < recs.size(); i++)
+ {
+ cout << recs[i] << endl;
+ }
+ }
+ else
+ {
+ sleepSeconds(1);
+ }
+ }
+ else
+ {
+ if(queue->isRecoveryNeeded())
+ {
+ delete queue;
+ queue = new PersistentMessageDequeue("");
+ if(!queue->init(true, msgQueueName))
+ {
+ cerr << "Error initializing message queue after error!" << endl;
+ break;
+ }
+ }
+ else
+ {
+ cerr << "Error dequeuing!" << endl;
+ break;
+ }
+ }
+ }
+ }
+ else
+ {
+ cerr << "Error initializing message queue!" << endl;
+ }
+ delete queue;
+}
+
+
+/* ====================================================================
+ * The Vovida Software License, Version 1.0
+ *
+ * Copyright (c) 2000-2012
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * 3. The names "VOCAL", "Vovida Open Communication Application Library",
+ * and "Vovida Open Communication Application Library (VOCAL)" must
+ * not be used to endorse or promote products derived from this
+ * software without prior written permission. For written
+ * permission, please contact vocal@xxxxxxxxxx.
+ *
+ * 4. Products derived from this software may not be called "VOCAL", nor
+ * may "VOCAL" appear in their name, without prior written
+ * permission of Vovida Networks, Inc.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESSED OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, TITLE AND
+ * NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT SHALL VOVIDA
+ * NETWORKS, INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT DAMAGES
+ * IN EXCESS OF $1,000, NOR FOR ANY INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
+ * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by Vovida
+ * Networks, Inc. and many individuals on behalf of Vovida Networks,
+ * Inc. For more information on Vovida Networks, Inc., please see
+ * <http://www.vovida.org/>.
+ *
+ */
+/*
+ * vi: set shiftwidth=3 expandtab:
+ */
Property changes on: repro/accountingconsumers/queuetostream.cpp
___________________________________________________________________
Added: svn:eol-style
+ native
Index: repro/accountingconsumers/Makefile.am
===================================================================
--- repro/accountingconsumers/Makefile.am (.../branches/resiprocate-1.8) (revision 0)
+++ repro/accountingconsumers/Makefile.am (.../main) (revision 9855)
@@ -0,0 +1,63 @@
+# $Id$
+
+EXTRA_DIST = *.vcxproj *.vcxproj.filters
+EXTRA_DIST += *.vcproj
+
+#AM_CXXFLAGS = -DUSE_ARES
+
+sbin_PROGRAMS = queuetostream
+queuetostream_SOURCES = queuetostream.cpp
+queuetostream_LDADD = ../librepro.la
+queuetostream_LDADD += ../../resip/dum/libdum.la
+queuetostream_LDADD += ../../resip/stack/libresip.la ../../rutil/librutil.la
+queuetostream_LDADD += @LIBSSL_LIBADD@ -lpthread
+
+##############################################################################
+#
+# The Vovida Software License, Version 1.0
+# Copyright (c) 2000-2007 Vovida Networks, Inc. All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+#
+# 1. Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+#
+# 2. Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in
+# the documentation and/or other materials provided with the
+# distribution.
+#
+# 3. The names "VOCAL", "Vovida Open Communication Application Library",
+# and "Vovida Open Communication Application Library (VOCAL)" must
+# not be used to endorse or promote products derived from this
+# software without prior written permission. For written
+# permission, please contact vocal@xxxxxxxxxx.
+#
+# 4. Products derived from this software may not be called "VOCAL", nor
+# may "VOCAL" appear in their name, without prior written
+# permission of Vovida Networks, Inc.
+#
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESSED OR IMPLIED
+# WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+# OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, TITLE AND
+# NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT SHALL VOVIDA
+# NETWORKS, INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT DAMAGES
+# IN EXCESS OF $1,000, NOR FOR ANY INDIRECT, INCIDENTAL, SPECIAL,
+# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+# PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+# OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
+# USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
+# DAMAGE.
+#
+# ====================================================================
+#
+# This software consists of voluntary contributions made by Vovida
+# Networks, Inc. and many individuals on behalf of Vovida Networks,
+# Inc. For more information on Vovida Networks, Inc., please see
+# <http://www.vovida.org/>.
+#
+##############################################################################
Index: repro/accountingconsumers/queuetostream_10_0.vcxproj
===================================================================
--- repro/accountingconsumers/queuetostream_10_0.vcxproj (.../branches/resiprocate-1.8) (revision 0)
+++ repro/accountingconsumers/queuetostream_10_0.vcxproj (.../main) (revision 9855)
@@ -0,0 +1,218 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <ItemGroup Label="ProjectConfigurations">
+ <ProjectConfiguration Include="Debug|Win32">
+ <Configuration>Debug</Configuration>
+ <Platform>Win32</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Release|Win32">
+ <Configuration>Release</Configuration>
+ <Platform>Win32</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="SSL-Debug|Win32">
+ <Configuration>SSL-Debug</Configuration>
+ <Platform>Win32</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="SSL-Release|Win32">
+ <Configuration>SSL-Release</Configuration>
+ <Platform>Win32</Platform>
+ </ProjectConfiguration>
+ </ItemGroup>
+ <PropertyGroup Label="Globals">
+ <ProjectName>queuetostream</ProjectName>
+ <ProjectGuid>{02C11EC5-9AB9-44F1-9B60-B719C1728356}</ProjectGuid>
+ <RootNamespace>queuetostream</RootNamespace>
+ <Keyword>Win32Proj</Keyword>
+ </PropertyGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='SSL-Release|Win32'" Label="Configuration">
+ <ConfigurationType>Application</ConfigurationType>
+ <CharacterSet>MultiByte</CharacterSet>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='SSL-Debug|Win32'" Label="Configuration">
+ <ConfigurationType>Application</ConfigurationType>
+ <CharacterSet>MultiByte</CharacterSet>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
+ <ConfigurationType>Application</ConfigurationType>
+ <CharacterSet>MultiByte</CharacterSet>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
+ <ConfigurationType>Application</ConfigurationType>
+ <CharacterSet>MultiByte</CharacterSet>
+ </PropertyGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
+ <ImportGroup Label="ExtensionSettings">
+ </ImportGroup>
+ <ImportGroup Condition="'$(Configuration)|$(Platform)'=='SSL-Release|Win32'" Label="PropertySheets">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ <Import Project="$(VCTargetsPath)Microsoft.CPP.UpgradeFromVC71.props" />
+ </ImportGroup>
+ <ImportGroup Condition="'$(Configuration)|$(Platform)'=='SSL-Debug|Win32'" Label="PropertySheets">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ <Import Project="$(VCTargetsPath)Microsoft.CPP.UpgradeFromVC71.props" />
+ </ImportGroup>
+ <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="PropertySheets">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ <Import Project="$(VCTargetsPath)Microsoft.CPP.UpgradeFromVC71.props" />
+ </ImportGroup>
+ <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="PropertySheets">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ <Import Project="$(VCTargetsPath)Microsoft.CPP.UpgradeFromVC71.props" />
+ </ImportGroup>
+ <PropertyGroup Label="UserMacros" />
+ <PropertyGroup>
+ <_ProjectFileVersion>10.0.40219.1</_ProjectFileVersion>
+ <OutDir Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Debug\</OutDir>
+ <IntDir Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Debug\</IntDir>
+ <LinkIncremental Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</LinkIncremental>
+ <OutDir Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">Release\</OutDir>
+ <IntDir Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">Release\</IntDir>
+ <LinkIncremental Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">false</LinkIncremental>
+ <OutDir Condition="'$(Configuration)|$(Platform)'=='SSL-Debug|Win32'">$(Configuration)\</OutDir>
+ <IntDir Condition="'$(Configuration)|$(Platform)'=='SSL-Debug|Win32'">$(Configuration)\</IntDir>
+ <LinkIncremental Condition="'$(Configuration)|$(Platform)'=='SSL-Debug|Win32'">true</LinkIncremental>
+ <OutDir Condition="'$(Configuration)|$(Platform)'=='SSL-Release|Win32'">$(Configuration)\</OutDir>
+ <IntDir Condition="'$(Configuration)|$(Platform)'=='SSL-Release|Win32'">$(Configuration)\</IntDir>
+ <LinkIncremental Condition="'$(Configuration)|$(Platform)'=='SSL-Release|Win32'">false</LinkIncremental>
+ <CodeAnalysisRuleSet Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">AllRules.ruleset</CodeAnalysisRuleSet>
+ <CodeAnalysisRules Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" />
+ <CodeAnalysisRuleAssemblies Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" />
+ <CodeAnalysisRuleSet Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">AllRules.ruleset</CodeAnalysisRuleSet>
+ <CodeAnalysisRules Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" />
+ <CodeAnalysisRuleAssemblies Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" />
+ <CodeAnalysisRuleSet Condition="'$(Configuration)|$(Platform)'=='SSL-Debug|Win32'">AllRules.ruleset</CodeAnalysisRuleSet>
+ <CodeAnalysisRules Condition="'$(Configuration)|$(Platform)'=='SSL-Debug|Win32'" />
+ <CodeAnalysisRuleAssemblies Condition="'$(Configuration)|$(Platform)'=='SSL-Debug|Win32'" />
+ <CodeAnalysisRuleSet Condition="'$(Configuration)|$(Platform)'=='SSL-Release|Win32'">AllRules.ruleset</CodeAnalysisRuleSet>
+ <CodeAnalysisRules Condition="'$(Configuration)|$(Platform)'=='SSL-Release|Win32'" />
+ <CodeAnalysisRuleAssemblies Condition="'$(Configuration)|$(Platform)'=='SSL-Release|Win32'" />
+ </PropertyGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <ClCompile>
+ <AdditionalOptions>/MP %(AdditionalOptions)</AdditionalOptions>
+ <Optimization>Disabled</Optimization>
+ <AdditionalIncludeDirectories>$(ProjectDir)../../;$(ProjectDir)../../contrib/db/build_windows;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ <PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;USE_IPV6;LEAK_CHECK;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <MinimalRebuild>false</MinimalRebuild>
+ <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
+ <RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>
+ <RuntimeTypeInfo>true</RuntimeTypeInfo>
+ <PrecompiledHeader>
+ </PrecompiledHeader>
+ <WarningLevel>Level3</WarningLevel>
+ <DebugInformationFormat>EditAndContinue</DebugInformationFormat>
+ </ClCompile>
+ <Link>
+ <AdditionalDependencies>Ws2_32.lib;Iphlpapi.lib;winmm.lib;Dnsapi.lib;%(AdditionalDependencies)</AdditionalDependencies>
+ <OutputFile>$(OutDir)queuetostream.exe</OutputFile>
+ <AdditionalLibraryDirectories>%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
+ <GenerateDebugInformation>true</GenerateDebugInformation>
+ <ProgramDatabaseFile>$(OutDir)queuetostream.pdb</ProgramDatabaseFile>
+ <SubSystem>Console</SubSystem>
+ <RandomizedBaseAddress>false</RandomizedBaseAddress>
+ <DataExecutionPrevention>
+ </DataExecutionPrevention>
+ <TargetMachine>MachineX86</TargetMachine>
+ </Link>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <ClCompile>
+ <AdditionalOptions>/MP %(AdditionalOptions)</AdditionalOptions>
+ <AdditionalIncludeDirectories>$(ProjectDir)../../;$(ProjectDir)../../contrib/db/build_windows;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ <PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;USE_IPV6;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <MinimalRebuild>false</MinimalRebuild>
+ <RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
+ <RuntimeTypeInfo>true</RuntimeTypeInfo>
+ <PrecompiledHeader>
+ </PrecompiledHeader>
+ <WarningLevel>Level3</WarningLevel>
+ <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
+ </ClCompile>
+ <Link>
+ <AdditionalDependencies>Ws2_32.lib;Iphlpapi.lib;winmm.lib;Dnsapi.lib;%(AdditionalDependencies)</AdditionalDependencies>
+ <OutputFile>$(OutDir)queuetostream.exe</OutputFile>
+ <AdditionalLibraryDirectories>%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
+ <GenerateDebugInformation>true</GenerateDebugInformation>
+ <SubSystem>Console</SubSystem>
+ <OptimizeReferences>true</OptimizeReferences>
+ <EnableCOMDATFolding>true</EnableCOMDATFolding>
+ <RandomizedBaseAddress>false</RandomizedBaseAddress>
+ <DataExecutionPrevention>
+ </DataExecutionPrevention>
+ <TargetMachine>MachineX86</TargetMachine>
+ </Link>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='SSL-Debug|Win32'">
+ <ClCompile>
+ <AdditionalOptions>/MP %(AdditionalOptions)</AdditionalOptions>
+ <Optimization>Disabled</Optimization>
+ <AdditionalIncludeDirectories>$(ProjectDir)../../;$(ProjectDir)../../contrib/db/build_windows;$(ProjectDir)../../contrib/openssl/include;$(ProjectDir)../../contrib/openssl/inc32;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ <PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;USE_SSL;USE_IPV6;LEAK_CHECK;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <MinimalRebuild>false</MinimalRebuild>
+ <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
+ <RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>
+ <RuntimeTypeInfo>true</RuntimeTypeInfo>
+ <PrecompiledHeader>
+ </PrecompiledHeader>
+ <WarningLevel>Level3</WarningLevel>
+ <DebugInformationFormat>EditAndContinue</DebugInformationFormat>
+ </ClCompile>
+ <Link>
+ <AdditionalDependencies>Ws2_32.lib;Dnsapi.lib;Iphlpapi.lib;winmm.lib;crypt32.lib;$(ProjectDir)..\..\contrib\openssl\lib\vc\static\libeay32MDd.lib;$(ProjectDir)..\..\contrib\openssl\lib\vc\static\ssleay32MDd.lib;%(AdditionalDependencies)</AdditionalDependencies>
+ <OutputFile>$(OutDir)queuetostream.exe</OutputFile>
+ <AdditionalLibraryDirectories>%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
+ <GenerateDebugInformation>true</GenerateDebugInformation>
+ <ProgramDatabaseFile>$(OutDir)queuetostream.pdb</ProgramDatabaseFile>
+ <SubSystem>Console</SubSystem>
+ <RandomizedBaseAddress>false</RandomizedBaseAddress>
+ <DataExecutionPrevention>
+ </DataExecutionPrevention>
+ <TargetMachine>MachineX86</TargetMachine>
+ </Link>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='SSL-Release|Win32'">
+ <ClCompile>
+ <AdditionalOptions>/MP %(AdditionalOptions)</AdditionalOptions>
+ <AdditionalIncludeDirectories>$(ProjectDir)../../;$(ProjectDir)../../contrib/db/build_windows;$(ProjectDir)../../contrib/openssl/include;$(ProjectDir)../../contrib/openssl/inc32;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ <PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;USE_SSL;USE_IPV6;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <MinimalRebuild>false</MinimalRebuild>
+ <RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
+ <RuntimeTypeInfo>true</RuntimeTypeInfo>
+ <PrecompiledHeader>
+ </PrecompiledHeader>
+ <WarningLevel>Level3</WarningLevel>
+ <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
+ </ClCompile>
+ <Link>
+ <AdditionalDependencies>Ws2_32.lib;Dnsapi.lib;Iphlpapi.lib;winmm.lib;crypt32.lib;$(ProjectDir)..\..\contrib\openssl\lib\vc\static\libeay32MD.lib;$(ProjectDir)..\..\contrib\openssl\lib\vc\static\ssleay32MD.lib;%(AdditionalDependencies)</AdditionalDependencies>
+ <OutputFile>$(OutDir)queuetostream.exe</OutputFile>
+ <AdditionalLibraryDirectories>%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
+ <GenerateDebugInformation>true</GenerateDebugInformation>
+ <SubSystem>Console</SubSystem>
+ <OptimizeReferences>true</OptimizeReferences>
+ <EnableCOMDATFolding>true</EnableCOMDATFolding>
+ <RandomizedBaseAddress>false</RandomizedBaseAddress>
+ <DataExecutionPrevention>
+ </DataExecutionPrevention>
+ <TargetMachine>MachineX86</TargetMachine>
+ </Link>
+ </ItemDefinitionGroup>
+ <ItemGroup>
+ <ClCompile Include="queuetostream.cpp" />
+ </ItemGroup>
+ <ItemGroup>
+ <ProjectReference Include="..\..\contrib\db\build_windows\db_static_10_0.vcxproj">
+ <Project>{9e5a7645-1502-4467-91f8-bcf2eb06ef72}</Project>
+ </ProjectReference>
+ <ProjectReference Include="..\..\rutil\rutil_10_0.vcxproj">
+ <Project>{3d0e5ceb-93dc-4fdb-918b-d08fa369e106}</Project>
+ </ProjectReference>
+ <ProjectReference Include="..\reprolib_10_0.vcxproj">
+ <Project>{31b0654f-e08e-405f-909f-80f86cb14b9e}</Project>
+ </ProjectReference>
+ </ItemGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
+ <ImportGroup Label="ExtensionTargets">
+ </ImportGroup>
+</Project>
\ No newline at end of file
Index: repro/accountingconsumers/queuetostream_9_0.vcproj
===================================================================
--- repro/accountingconsumers/queuetostream_9_0.vcproj (.../branches/resiprocate-1.8) (revision 0)
+++ repro/accountingconsumers/queuetostream_9_0.vcproj (.../main) (revision 9855)
@@ -0,0 +1,374 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioProject
+ ProjectType="Visual C++"
+ Version="9.00"
+ Name="queuetostream"
+ ProjectGUID="{02C11EC5-9AB9-44F1-9B60-B719C1728356}"
+ RootNamespace="queuetostream"
+ Keyword="Win32Proj"
+ TargetFrameworkVersion="131072"
+ >
+ <Platforms>
+ <Platform
+ Name="Win32"
+ />
+ </Platforms>
+ <ToolFiles>
+ </ToolFiles>
+ <Configurations>
+ <Configuration
+ Name="Debug|Win32"
+ OutputDirectory="Debug"
+ IntermediateDirectory="Debug"
+ ConfigurationType="1"
+ InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops"
+ CharacterSet="2"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalOptions="/MP"
+ Optimization="0"
+ AdditionalIncludeDirectories=""$(ProjectDir)../../";"$(ProjectDir)../../contrib/db/build_windows""
+ PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE;USE_IPV6;LEAK_CHECK"
+ MinimalRebuild="false"
+ BasicRuntimeChecks="3"
+ RuntimeLibrary="3"
+ RuntimeTypeInfo="true"
+ UsePrecompiledHeader="0"
+ WarningLevel="3"
+ Detect64BitPortabilityProblems="false"
+ DebugInformationFormat="4"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalDependencies="Ws2_32.lib Iphlpapi.lib winmm.lib Dnsapi.lib"
+ OutputFile="$(OutDir)/queuetostream.exe"
+ LinkIncremental="2"
+ AdditionalLibraryDirectories=""
+ GenerateDebugInformation="true"
+ ProgramDatabaseFile="$(OutDir)/queuetostream.pdb"
+ SubSystem="1"
+ RandomizedBaseAddress="1"
+ DataExecutionPrevention="0"
+ TargetMachine="1"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Release|Win32"
+ OutputDirectory="Release"
+ IntermediateDirectory="Release"
+ ConfigurationType="1"
+ InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops"
+ CharacterSet="2"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalOptions="/MP"
+ AdditionalIncludeDirectories=""$(ProjectDir)../../";"$(ProjectDir)../../contrib/db/build_windows""
+ PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE;USE_IPV6"
+ MinimalRebuild="false"
+ RuntimeLibrary="2"
+ RuntimeTypeInfo="true"
+ UsePrecompiledHeader="0"
+ WarningLevel="3"
+ Detect64BitPortabilityProblems="false"
+ DebugInformationFormat="3"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalDependencies="Ws2_32.lib Iphlpapi.lib winmm.lib Dnsapi.lib"
+ OutputFile="$(OutDir)/queuetostream.exe"
+ LinkIncremental="1"
+ AdditionalLibraryDirectories=""
+ GenerateDebugInformation="true"
+ SubSystem="1"
+ OptimizeReferences="2"
+ EnableCOMDATFolding="2"
+ RandomizedBaseAddress="1"
+ DataExecutionPrevention="0"
+ TargetMachine="1"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="SSL-Debug|Win32"
+ OutputDirectory="$(ConfigurationName)"
+ IntermediateDirectory="$(ConfigurationName)"
+ ConfigurationType="1"
+ InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops"
+ CharacterSet="2"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalOptions="/MP"
+ Optimization="0"
+ AdditionalIncludeDirectories=""$(ProjectDir)../../";"$(ProjectDir)../../contrib/db/build_windows";"$(ProjectDir)../../contrib/openssl/include";"$(ProjectDir)../../contrib/openssl/inc32""
+ PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE;USE_SSL;USE_IPV6;LEAK_CHECK"
+ MinimalRebuild="false"
+ BasicRuntimeChecks="3"
+ RuntimeLibrary="3"
+ RuntimeTypeInfo="true"
+ UsePrecompiledHeader="0"
+ WarningLevel="3"
+ Detect64BitPortabilityProblems="false"
+ DebugInformationFormat="4"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalDependencies="Ws2_32.lib Dnsapi.lib Iphlpapi.lib winmm.lib crypt32.lib "$(ProjectDir)..\..\contrib\openssl\lib\vc\static\libeay32MDd.lib" "$(ProjectDir)..\..\contrib\openssl\lib\vc\static\ssleay32MDd.lib""
+ OutputFile="$(OutDir)/queuetostream.exe"
+ LinkIncremental="2"
+ AdditionalLibraryDirectories=""
+ GenerateDebugInformation="true"
+ ProgramDatabaseFile="$(OutDir)/queuetostream.pdb"
+ SubSystem="1"
+ RandomizedBaseAddress="1"
+ DataExecutionPrevention="0"
+ TargetMachine="1"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="SSL-Release|Win32"
+ OutputDirectory="$(ConfigurationName)"
+ IntermediateDirectory="$(ConfigurationName)"
+ ConfigurationType="1"
+ InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops"
+ CharacterSet="2"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalOptions="/MP"
+ AdditionalIncludeDirectories=""$(ProjectDir)../../";"$(ProjectDir)../../contrib/db/build_windows";"$(ProjectDir)../../contrib/openssl/include";"$(ProjectDir)../../contrib/openssl/inc32""
+ PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE;USE_SSL;USE_IPV6"
+ MinimalRebuild="false"
+ RuntimeLibrary="2"
+ RuntimeTypeInfo="true"
+ UsePrecompiledHeader="0"
+ WarningLevel="3"
+ Detect64BitPortabilityProblems="false"
+ DebugInformationFormat="3"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalDependencies="Ws2_32.lib Dnsapi.lib Iphlpapi.lib winmm.lib crypt32.lib "$(ProjectDir)..\..\contrib\openssl\lib\vc\static\libeay32MD.lib" "$(ProjectDir)..\..\contrib\openssl\lib\vc\static\ssleay32MD.lib""
+ OutputFile="$(OutDir)/queuetostream.exe"
+ LinkIncremental="1"
+ AdditionalLibraryDirectories=""
+ GenerateDebugInformation="true"
+ SubSystem="1"
+ OptimizeReferences="2"
+ EnableCOMDATFolding="2"
+ RandomizedBaseAddress="1"
+ DataExecutionPrevention="0"
+ TargetMachine="1"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ </Configurations>
+ <References>
+ </References>
+ <Files>
+ <Filter
+ Name="Source Files"
+ Filter="cpp;c;cxx;def;odl;idl;hpj;bat;asm;asmx"
+ UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
+ >
+ <File
+ RelativePath=".\queuetostream.cpp"
+ >
+ </File>
+ </Filter>
+ <Filter
+ Name="Header Files"
+ Filter="h;hpp;hxx;hm;inl;inc;xsd"
+ UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"
+ >
+ </Filter>
+ <Filter
+ Name="Resource Files"
+ Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx"
+ UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}"
+ >
+ </Filter>
+ </Files>
+ <Globals>
+ </Globals>
+</VisualStudioProject>
Index: repro/RequestContext.hxx
===================================================================
--- repro/RequestContext.hxx (.../branches/resiprocate-1.8) (revision 9855)
+++ repro/RequestContext.hxx (.../main) (revision 9855)
@@ -66,6 +66,9 @@
void updateTimerC();
bool mInitialTimerCSet;
+ void setSessionCreatedEventSent() { mSessionCreatedEventSent = true; }
+ void setSessionEstablishedEventSent() { mSessionEstablishedEventSent = true; }
+
void postTimedMessage(std::auto_ptr<resip::ApplicationMessage> msg,int seconds);
// Accessor for per-requset extensible state storage for monkeys
@@ -96,6 +99,8 @@
ResponseContext mResponseContext;
int mTCSerial;
resip::KeyValueStore mKeyValueStore;
+ bool mSessionCreatedEventSent;
+ bool mSessionEstablishedEventSent;
typedef std::vector<ProcessorChain::Chain::iterator>
Index: repro/Makefile.am
===================================================================
--- repro/Makefile.am (.../branches/resiprocate-1.8) (revision 9855)
+++ repro/Makefile.am (.../main) (revision 9855)
@@ -17,7 +17,7 @@
EXTRA_DIST += repro.config
EXTRA_DIST += create_mysql_reprodb.sql
-SUBDIRS = . test reprocmd
+SUBDIRS = . test reprocmd accountingconsumers
#AM_CXXFLAGS = -DUSE_ARES
@@ -56,6 +56,7 @@
WebAdmin.cxx \
WebAdminThread.cxx \
\
+ AccountingCollector.cxx \
Proxy.cxx \
Registrar.cxx \
RegSyncClient.cxx \
@@ -74,6 +75,7 @@
XmlRpcServerBase.cxx \
Dispatcher.cxx \
OutboundTarget.cxx \
+ PersistentMessageQueue.cxx \
QValueTarget.cxx \
\
monkeys/CertificateAuthenticator.cxx \
@@ -95,6 +97,7 @@
reproincludedir = $(includedir)/repro
nobase_reproinclude_HEADERS = AbstractDb.hxx \
+ AccountingCollector.hxx \
Ack200DoneMessage.hxx \
AclStore.hxx \
AsyncProcessor.hxx \
@@ -128,6 +131,7 @@
monkeys/MessageSilo.hxx \
MySqlDb.hxx \
OutboundTarget.hxx \
+ PersistentMessageQueue.hxx \
ProcessorChain.hxx \
Processor.hxx \
ProcessorMessage.hxx \
Index: reSIProcate_10_0.sln
===================================================================
--- reSIProcate_10_0.sln (.../branches/resiprocate-1.8) (revision 9855)
+++ reSIProcate_10_0.sln (.../main) (revision 9855)
@@ -26,7 +26,7 @@
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "reprolib", "repro\reprolib_10_0.vcxproj", "{31B0654F-E08E-405F-909F-80F86CB14B9E}"
EndProject
-Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "popt", "contrib\popt\popt_10_0.vcxproj", "{BD9B6DDA-3ACC-A361-1FA3-12FB51B48952}"
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "popt", "contrib\popt\popt_10_0.vcxproj", "{F65E692D-77B0-B1C9-EE09-2FF98019FEF0}"
EndProject
Project("{54435603-DBB4-11D2-8724-00A0C9A8B90C}") = "ReproSetupx64", "repro\WinSetupx64\Setupx64_10_0.vdproj", "{91601068-BE73-4BE9-8030-143F4620E907}"
EndProject
@@ -36,6 +36,10 @@
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "GeoIP", "contrib\GeoIP\GeoIP_10_0.vcxproj", "{6527D843-EE53-4F1E-B0A9-12ABBA8E75CC}"
EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "repro", "repro", "{1293EE21-39D4-4D31-B6D3-78D7865E0F85}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "queuetostream", "repro\accountingconsumers\queuetostream_10_0.vcxproj", "{02C11EC5-9AB9-44F1-9B60-B719C1728356}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Win32 = Debug|Win32
@@ -252,22 +256,22 @@
{31B0654F-E08E-405F-909F-80F86CB14B9E}.SSL-Release|Win32.Build.0 = SSL-Release|Win32
{31B0654F-E08E-405F-909F-80F86CB14B9E}.SSL-Release|x64.ActiveCfg = SSL-Release|x64
{31B0654F-E08E-405F-909F-80F86CB14B9E}.SSL-Release|x64.Build.0 = SSL-Release|x64
- {BD9B6DDA-3ACC-A361-1FA3-12FB51B48952}.Debug|Win32.ActiveCfg = Debug|Win32
- {BD9B6DDA-3ACC-A361-1FA3-12FB51B48952}.Debug|Win32.Build.0 = Debug|Win32
- {BD9B6DDA-3ACC-A361-1FA3-12FB51B48952}.Debug|x64.ActiveCfg = Debug|x64
- {BD9B6DDA-3ACC-A361-1FA3-12FB51B48952}.Debug|x64.Build.0 = Debug|x64
- {BD9B6DDA-3ACC-A361-1FA3-12FB51B48952}.Release|Win32.ActiveCfg = Release|Win32
- {BD9B6DDA-3ACC-A361-1FA3-12FB51B48952}.Release|Win32.Build.0 = Release|Win32
- {BD9B6DDA-3ACC-A361-1FA3-12FB51B48952}.Release|x64.ActiveCfg = Release|x64
- {BD9B6DDA-3ACC-A361-1FA3-12FB51B48952}.Release|x64.Build.0 = Release|x64
- {BD9B6DDA-3ACC-A361-1FA3-12FB51B48952}.SSL-Debug|Win32.ActiveCfg = Debug|Win32
- {BD9B6DDA-3ACC-A361-1FA3-12FB51B48952}.SSL-Debug|Win32.Build.0 = Debug|Win32
- {BD9B6DDA-3ACC-A361-1FA3-12FB51B48952}.SSL-Debug|x64.ActiveCfg = Debug|x64
- {BD9B6DDA-3ACC-A361-1FA3-12FB51B48952}.SSL-Debug|x64.Build.0 = Debug|x64
- {BD9B6DDA-3ACC-A361-1FA3-12FB51B48952}.SSL-Release|Win32.ActiveCfg = Release|Win32
- {BD9B6DDA-3ACC-A361-1FA3-12FB51B48952}.SSL-Release|Win32.Build.0 = Release|Win32
- {BD9B6DDA-3ACC-A361-1FA3-12FB51B48952}.SSL-Release|x64.ActiveCfg = Release|x64
- {BD9B6DDA-3ACC-A361-1FA3-12FB51B48952}.SSL-Release|x64.Build.0 = Release|x64
+ {F65E692D-77B0-B1C9-EE09-2FF98019FEF0}.Debug|Win32.ActiveCfg = Debug|Win32
+ {F65E692D-77B0-B1C9-EE09-2FF98019FEF0}.Debug|Win32.Build.0 = Debug|Win32
+ {F65E692D-77B0-B1C9-EE09-2FF98019FEF0}.Debug|x64.ActiveCfg = Debug|x64
+ {F65E692D-77B0-B1C9-EE09-2FF98019FEF0}.Debug|x64.Build.0 = Debug|x64
+ {F65E692D-77B0-B1C9-EE09-2FF98019FEF0}.Release|Win32.ActiveCfg = Release|Win32
+ {F65E692D-77B0-B1C9-EE09-2FF98019FEF0}.Release|Win32.Build.0 = Release|Win32
+ {F65E692D-77B0-B1C9-EE09-2FF98019FEF0}.Release|x64.ActiveCfg = Release|x64
+ {F65E692D-77B0-B1C9-EE09-2FF98019FEF0}.Release|x64.Build.0 = Release|x64
+ {F65E692D-77B0-B1C9-EE09-2FF98019FEF0}.SSL-Debug|Win32.ActiveCfg = Debug|Win32
+ {F65E692D-77B0-B1C9-EE09-2FF98019FEF0}.SSL-Debug|Win32.Build.0 = Debug|Win32
+ {F65E692D-77B0-B1C9-EE09-2FF98019FEF0}.SSL-Debug|x64.ActiveCfg = Debug|x64
+ {F65E692D-77B0-B1C9-EE09-2FF98019FEF0}.SSL-Debug|x64.Build.0 = Debug|x64
+ {F65E692D-77B0-B1C9-EE09-2FF98019FEF0}.SSL-Release|Win32.ActiveCfg = Release|Win32
+ {F65E692D-77B0-B1C9-EE09-2FF98019FEF0}.SSL-Release|Win32.Build.0 = Release|Win32
+ {F65E692D-77B0-B1C9-EE09-2FF98019FEF0}.SSL-Release|x64.ActiveCfg = Release|x64
+ {F65E692D-77B0-B1C9-EE09-2FF98019FEF0}.SSL-Release|x64.Build.0 = Release|x64
{91601068-BE73-4BE9-8030-143F4620E907}.Debug|Win32.ActiveCfg = Debug
{91601068-BE73-4BE9-8030-143F4620E907}.Debug|x64.ActiveCfg = Debug
{91601068-BE73-4BE9-8030-143F4620E907}.Debug|x64.Build.0 = Debug
@@ -322,8 +326,28 @@
{6527D843-EE53-4F1E-B0A9-12ABBA8E75CC}.SSL-Release|Win32.ActiveCfg = Release|Win32
{6527D843-EE53-4F1E-B0A9-12ABBA8E75CC}.SSL-Release|Win32.Build.0 = Release|Win32
{6527D843-EE53-4F1E-B0A9-12ABBA8E75CC}.SSL-Release|x64.ActiveCfg = Release|Win32
+ {02C11EC5-9AB9-44F1-9B60-B719C1728356}.Debug|Win32.ActiveCfg = Debug|Win32
+ {02C11EC5-9AB9-44F1-9B60-B719C1728356}.Debug|Win32.Build.0 = Debug|Win32
+ {02C11EC5-9AB9-44F1-9B60-B719C1728356}.Debug|x64.ActiveCfg = Debug|Win32
+ {02C11EC5-9AB9-44F1-9B60-B719C1728356}.Release|Win32.ActiveCfg = Release|Win32
+ {02C11EC5-9AB9-44F1-9B60-B719C1728356}.Release|Win32.Build.0 = Release|Win32
+ {02C11EC5-9AB9-44F1-9B60-B719C1728356}.Release|x64.ActiveCfg = Release|Win32
+ {02C11EC5-9AB9-44F1-9B60-B719C1728356}.SSL-Debug|Win32.ActiveCfg = SSL-Debug|Win32
+ {02C11EC5-9AB9-44F1-9B60-B719C1728356}.SSL-Debug|Win32.Build.0 = SSL-Debug|Win32
+ {02C11EC5-9AB9-44F1-9B60-B719C1728356}.SSL-Debug|x64.ActiveCfg = SSL-Debug|Win32
+ {02C11EC5-9AB9-44F1-9B60-B719C1728356}.SSL-Release|Win32.ActiveCfg = SSL-Release|Win32
+ {02C11EC5-9AB9-44F1-9B60-B719C1728356}.SSL-Release|Win32.Build.0 = SSL-Release|Win32
+ {02C11EC5-9AB9-44F1-9B60-B719C1728356}.SSL-Release|x64.ActiveCfg = SSL-Release|Win32
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
+ GlobalSection(NestedProjects) = preSolution
+ {31B0654F-E08E-405F-909F-80F86CB14B9E} = {1293EE21-39D4-4D31-B6D3-78D7865E0F85}
+ {16CD976A-5D3B-4329-88BA-A32560CDFCC8} = {1293EE21-39D4-4D31-B6D3-78D7865E0F85}
+ {9D8D2649-213F-49D3-A8B0-C1849C611654} = {1293EE21-39D4-4D31-B6D3-78D7865E0F85}
+ {02C11EC5-9AB9-44F1-9B60-B719C1728356} = {1293EE21-39D4-4D31-B6D3-78D7865E0F85}
+ {02954DA6-5079-4717-BC3D-B3ACA815CFED} = {1293EE21-39D4-4D31-B6D3-78D7865E0F85}
+ {91601068-BE73-4BE9-8030-143F4620E907} = {1293EE21-39D4-4D31-B6D3-78D7865E0F85}
+ EndGlobalSection
EndGlobal
Index: rutil/cajun/ReleaseNotes.txt
===================================================================
--- rutil/cajun/ReleaseNotes.txt (.../branches/resiprocate-1.8) (revision 0)
+++ rutil/cajun/ReleaseNotes.txt (.../main) (revision 9855)
@@ -0,0 +1,42 @@
+2.0.2 (12/04/2011)
+* Fixed exception text construction bug (pointer + offset, instead of std::string + std::string)
+* Fixed crash in UnknownElement::operator=
+* Fixed bug where object member names couldn't contain special characters
+* Fixed crash when parsing an incomplete document
+* Cosmetic changes to parser
+* Added proper BSD license text
+
+2.0.1 (11/17/2009)
+* A couple of Reader functions not inlined, sometimes resulting in linker duplicate symbols. Oops.
+
+2.0.0 (11/14/2009)
+* Redesign/simplicification of the element class relationships:
+ * Element/Element_T base class or *Imp classes eliminated. Originally necessary for aggregation by Object/Array, but now unnecessary with UnknownElement type
+ * json_cast<> functions eliminated. Static type safety relaxed, allowing more concise document data extraction code (dynamic type safety still completely maintained).
+ * Quick-Interpreter/-Builder classes eliminated. Equivalent functionality now in "UnknownElement", but now more accessible
+ In summary, simpler design, less code in library, less code necessary to utilize library. See test app for many more new examples.
+* Entire library is now inlined. Bound to be controversial, but...
+ * Modern compilers should eliminate redundant object code
+ * Fixes problems associated with different runtime libraries, library debug information, security & debug iterator compile-time options under MSVC++, among other things.
+ * Simply include the appropriate file & go - no linker settings to mess with.
+* Added 64-bit build targets for MSVC 8/9 test app, just because.
+* Scan/Parse exceptions moved into Reader class scope, and Parse exceptions fixed to always include bad token string
+* A few more random bug fixes
+* Tested under:
+ * MSVC++ 2005
+ * MSVC++ 2008
+ * GCC 4.4.0
+
+1.1.0 (08/30/2009)
+* Implemented operator == for all element types
+* Added makefile for building with g++ (thanks George Morgan).
+* Fixed a few compiler errors on non-Visual Studio compilers (my C++ wasn't as ANSI as I thought...)
+* Support for (non-standard) comments REMOVED
+* Support for Visual Studio 7.1 (2003) REMOVED
+* Fixed the "Unexpected token..." exception string (was gibberish)
+* Improvements to the QuickInterpreter & QuickBuilder interfaces
+* Elements now sanity-check themselves during operations and throw an exception accordingly, for example if an Object gets tricked into thinking it's an Array (reinterpret_cast, reading a document with an Array root element into an Object, etc)
+* Other random minor bug fixes & general cleanup
+
+1.0.0 (01/31/2009)
+* Initial release! Remaining work: better documentation, better test/sample app, yada yada
Property changes on: rutil/cajun/ReleaseNotes.txt
___________________________________________________________________
Added: svn:eol-style
+ native
Index: rutil/cajun/json/elements.h
===================================================================
--- rutil/cajun/json/elements.h (.../branches/resiprocate-1.8) (revision 0)
+++ rutil/cajun/json/elements.h (.../main) (revision 9855)
@@ -0,0 +1,299 @@
+/******************************************************************************
+
+Copyright (c) 2009-2010, Terry Caton
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+ * Neither the name of the projecct nor the names of its contributors
+ may be used to endorse or promote products derived from this software
+ without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+******************************************************************************/
+
+#pragma once
+
+#include <deque>
+#include <list>
+#include <string>
+#include <stdexcept>
+
+/*
+
+TODO:
+* better documentation (doxygen?)
+* Unicode support
+* parent element accessors
+
+*/
+
+namespace json
+{
+
+namespace Version
+{
+ enum { MAJOR = 2 };
+ enum { MINOR = 0 };
+ enum {ENGINEERING = 2 };
+}
+
+/////////////////////////////////////////////////
+// forward declarations (more info further below)
+
+
+class Visitor;
+class ConstVisitor;
+
+template <typename ValueTypeT>
+class TrivialType_T;
+
+typedef TrivialType_T<double> Number;
+typedef TrivialType_T<bool> Boolean;
+typedef TrivialType_T<std::string> String;
+
+class Object;
+class Array;
+class Null;
+
+
+
+/////////////////////////////////////////////////////////////////////////
+// Exception - base class for all JSON-related runtime errors
+
+class Exception : public std::runtime_error
+{
+public:
+ Exception(const std::string& sMessage);
+};
+
+
+
+
+/////////////////////////////////////////////////////////////////////////
+// UnknownElement - provides a typesafe surrogate for any of the JSON-
+// sanctioned element types. This class allows the Array and Object
+// class to effectively contain a heterogeneous set of child elements.
+// The cast operators provide convenient implicit downcasting, while
+// preserving dynamic type safety by throwing an exception during a
+// a bad cast.
+// The object & array element index operators (operators [std::string]
+// and [size_t]) provide convenient, quick access to child elements.
+// They are a logical extension of the cast operators. These child
+// element accesses can be chained together, allowing the following
+// (when document structure is well-known):
+// String str = objInvoices[1]["Customer"]["Company"];
+
+
+class UnknownElement
+{
+public:
+ UnknownElement();
+ UnknownElement(const UnknownElement& unknown);
+ UnknownElement(const Object& object);
+ UnknownElement(const Array& array);
+ UnknownElement(const Number& number);
+ UnknownElement(const Boolean& boolean);
+ UnknownElement(const String& string);
+ UnknownElement(const Null& null);
+
+ ~UnknownElement();
+
+ UnknownElement& operator = (const UnknownElement& unknown);
+
+ // implicit cast to actual element type. throws on failure
+ operator const Object& () const;
+ operator const Array& () const;
+ operator const Number& () const;
+ operator const Boolean& () const;
+ operator const String& () const;
+ operator const Null& () const;
+
+ // implicit cast to actual element type. *converts* on failure, and always returns success
+ operator Object& ();
+ operator Array& ();
+ operator Number& ();
+ operator Boolean& ();
+ operator String& ();
+ operator Null& ();
+
+ // provides quick access to children when real element type is object
+ UnknownElement& operator[] (const std::string& key);
+ const UnknownElement& operator[] (const std::string& key) const;
+
+ // provides quick access to children when real element type is array
+ UnknownElement& operator[] (size_t index);
+ const UnknownElement& operator[] (size_t index) const;
+
+ // implements visitor pattern
+ void Accept(ConstVisitor& visitor) const;
+ void Accept(Visitor& visitor);
+
+ // tests equality. first checks type, then value if possible
+ bool operator == (const UnknownElement& element) const;
+
+private:
+ class Imp;
+
+ template <typename ElementTypeT>
+ class Imp_T;
+
+ class CastVisitor;
+ class ConstCastVisitor;
+
+ template <typename ElementTypeT>
+ class CastVisitor_T;
+
+ template <typename ElementTypeT>
+ class ConstCastVisitor_T;
+
+ template <typename ElementTypeT>
+ const ElementTypeT& CastTo() const;
+
+ template <typename ElementTypeT>
+ ElementTypeT& ConvertTo();
+
+ Imp* m_pImp;
+};
+
+
+/////////////////////////////////////////////////////////////////////////////////
+// Array - mimics std::deque<UnknownElement>. The array contents are effectively
+// heterogeneous thanks to the ElementUnknown class. push_back has been replaced
+// by more generic insert functions.
+
+class Array
+{
+public:
+ typedef std::deque<UnknownElement> Elements;
+ typedef Elements::iterator iterator;
+ typedef Elements::const_iterator const_iterator;
+
+ iterator Begin();
+ iterator End();
+ const_iterator Begin() const;
+ const_iterator End() const;
+
+ iterator Insert(const UnknownElement& element, iterator itWhere);
+ iterator Insert(const UnknownElement& element);
+ iterator Erase(iterator itWhere);
+ void Resize(size_t newSize);
+ void Clear();
+
+ size_t Size() const;
+ bool Empty() const;
+
+ UnknownElement& operator[] (size_t index);
+ const UnknownElement& operator[] (size_t index) const;
+
+ bool operator == (const Array& array) const;
+
+private:
+ Elements m_Elements;
+};
+
+
+/////////////////////////////////////////////////////////////////////////////////
+// Object - mimics std::map<std::string, UnknownElement>. The member value
+// contents are effectively heterogeneous thanks to the UnknownElement class
+
+class Object
+{
+public:
+ struct Member {
+ Member(const std::string& nameIn = std::string(), const UnknownElement& elementIn = UnknownElement());
+
+ bool operator == (const Member& member) const;
+
+ std::string name;
+ UnknownElement element;
+ };
+
+ typedef std::list<Member> Members; // map faster, but does not preserve order
+ typedef Members::iterator iterator;
+ typedef Members::const_iterator const_iterator;
+
+ bool operator == (const Object& object) const;
+
+ iterator Begin();
+ iterator End();
+ const_iterator Begin() const;
+ const_iterator End() const;
+
+ size_t Size() const;
+ bool Empty() const;
+
+ iterator Find(const std::string& name);
+ const_iterator Find(const std::string& name) const;
+
+ iterator Insert(const Member& member);
+ iterator Insert(const Member& member, iterator itWhere);
+ iterator Erase(iterator itWhere);
+ void Clear();
+
+ UnknownElement& operator [](const std::string& name);
+ const UnknownElement& operator [](const std::string& name) const;
+
+private:
+ class Finder;
+
+ Members m_Members;
+};
+
+
+/////////////////////////////////////////////////////////////////////////////////
+// TrivialType_T - class template for encapsulates a simple data type, such as
+// a string, number, or boolean. Provides implicit const & noncost cast operators
+// for that type, allowing "DataTypeT type = trivialType;"
+
+
+template <typename DataTypeT>
+class TrivialType_T
+{
+public:
+ TrivialType_T(const DataTypeT& t = DataTypeT());
+
+ operator DataTypeT&();
+ operator const DataTypeT&() const;
+
+ DataTypeT& Value();
+ const DataTypeT& Value() const;
+
+ bool operator == (const TrivialType_T<DataTypeT>& trivial) const;
+
+private:
+ DataTypeT m_tValue;
+};
+
+
+
+/////////////////////////////////////////////////////////////////////////////////
+// Null - doesn't do much of anything but satisfy the JSON spec. It is the default
+// element type of UnknownElement
+
+class Null
+{
+public:
+ bool operator == (const Null& trivial) const;
+};
+
+
+} // End namespace
+
+
+#include "elements.inl"
Property changes on: rutil/cajun/json/elements.h
___________________________________________________________________
Added: svn:eol-style
+ native
Index: rutil/cajun/json/writer.h
===================================================================
--- rutil/cajun/json/writer.h (.../branches/resiprocate-1.8) (revision 0)
+++ rutil/cajun/json/writer.h (.../main) (revision 9855)
@@ -0,0 +1,78 @@
+/******************************************************************************
+
+Copyright (c) 2009-2010, Terry Caton
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+ * Neither the name of the projecct nor the names of its contributors
+ may be used to endorse or promote products derived from this software
+ without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+******************************************************************************/
+
+#pragma once
+
+#include "elements.h"
+#include "visitor.h"
+
+namespace json
+{
+
+class Writer : private ConstVisitor
+{
+public:
+ static void Write(const Object& object, std::ostream& ostr);
+ static void Write(const Array& array, std::ostream& ostr);
+ static void Write(const String& string, std::ostream& ostr);
+ static void Write(const Number& number, std::ostream& ostr);
+ static void Write(const Boolean& boolean, std::ostream& ostr);
+ static void Write(const Null& null, std::ostream& ostr);
+ static void Write(const UnknownElement& elementRoot, std::ostream& ostr);
+
+private:
+ Writer(std::ostream& ostr);
+
+ template <typename ElementTypeT>
+ static void Write_i(const ElementTypeT& element, std::ostream& ostr);
+
+ void Write_i(const Object& object);
+ void Write_i(const Array& array);
+ void Write_i(const String& string);
+ void Write_i(const Number& number);
+ void Write_i(const Boolean& boolean);
+ void Write_i(const Null& null);
+ void Write_i(const UnknownElement& unknown);
+
+ virtual void Visit(const Array& array);
+ virtual void Visit(const Object& object);
+ virtual void Visit(const Number& number);
+ virtual void Visit(const String& string);
+ virtual void Visit(const Boolean& boolean);
+ virtual void Visit(const Null& null);
+
+ std::ostream& m_ostr;
+ int m_nTabDepth;
+};
+
+
+} // End namespace
+
+
+#include "writer.inl"
\ No newline at end of file
Property changes on: rutil/cajun/json/writer.h
___________________________________________________________________
Added: svn:eol-style
+ native
Index: rutil/cajun/json/reader.inl
===================================================================
--- rutil/cajun/json/reader.inl (.../branches/resiprocate-1.8) (revision 0)
+++ rutil/cajun/json/reader.inl (.../main) (revision 9855)
@@ -0,0 +1,533 @@
+/******************************************************************************
+
+Copyright (c) 2009-2010, Terry Caton
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+ * Neither the name of the projecct nor the names of its contributors
+ may be used to endorse or promote products derived from this software
+ without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+******************************************************************************/
+
+#include <cassert>
+#include <set>
+#include <sstream>
+
+/*
+
+TODO:
+* better documentation
+* unicode character decoding
+
+*/
+
+namespace json
+{
+
+inline std::istream& operator >> (std::istream& istr, UnknownElement& elementRoot) {
+ Reader::Read(elementRoot, istr);
+ return istr;
+}
+
+inline Reader::Location::Location() :
+ m_nLine(0),
+ m_nLineOffset(0),
+ m_nDocOffset(0)
+{}
+
+
+//////////////////////
+// Reader::InputStream
+
+class Reader::InputStream // would be cool if we could inherit from std::istream & override "get"
+{
+public:
+ InputStream(std::istream& iStr) :
+ m_iStr(iStr) {}
+
+ // protect access to the input stream, so we can keeep track of document/line offsets
+ char Get(); // big, define outside
+ char Peek() {
+ assert(m_iStr.eof() == false); // enforce reading of only valid stream data
+ return m_iStr.peek();
+ }
+
+ bool EOS() {
+ m_iStr.peek(); // apparently eof flag isn't set until a character read is attempted. whatever.
+ return m_iStr.eof();
+ }
+
+ const Location& GetLocation() const { return m_Location; }
+
+private:
+ std::istream& m_iStr;
+ Location m_Location;
+};
+
+
+inline char Reader::InputStream::Get()
+{
+ assert(m_iStr.eof() == false); // enforce reading of only valid stream data
+ char c = m_iStr.get();
+
+ ++m_Location.m_nDocOffset;
+ if (c == '\n') {
+ ++m_Location.m_nLine;
+ m_Location.m_nLineOffset = 0;
+ }
+ else {
+ ++m_Location.m_nLineOffset;
+ }
+
+ return c;
+}
+
+
+
+//////////////////////
+// Reader::TokenStream
+
+class Reader::TokenStream
+{
+public:
+ TokenStream(const Tokens& tokens);
+
+ const Token& Peek();
+ const Token& Get();
+
+ bool EOS() const;
+
+private:
+ const Tokens& m_Tokens;
+ Tokens::const_iterator m_itCurrent;
+};
+
+
+inline Reader::TokenStream::TokenStream(const Tokens& tokens) :
+ m_Tokens(tokens),
+ m_itCurrent(tokens.begin())
+{}
+
+inline const Reader::Token& Reader::TokenStream::Peek() {
+ if (EOS())
+ {
+ const Token& lastToken = *m_Tokens.rbegin();
+ std::string sMessage = "Unexpected end of token stream";
+ throw ParseException(sMessage, lastToken.locBegin, lastToken.locEnd); // nowhere to point to
+ }
+ return *(m_itCurrent);
+}
+
+inline const Reader::Token& Reader::TokenStream::Get() {
+ const Token& token = Peek();
+ ++m_itCurrent;
+ return token;
+}
+
+inline bool Reader::TokenStream::EOS() const {
+ return m_itCurrent == m_Tokens.end();
+}
+
+///////////////////
+// Reader (finally)
+
+
+inline void Reader::Read(Object& object, std::istream& istr) { Read_i(object, istr); }
+inline void Reader::Read(Array& array, std::istream& istr) { Read_i(array, istr); }
+inline void Reader::Read(String& string, std::istream& istr) { Read_i(string, istr); }
+inline void Reader::Read(Number& number, std::istream& istr) { Read_i(number, istr); }
+inline void Reader::Read(Boolean& boolean, std::istream& istr) { Read_i(boolean, istr); }
+inline void Reader::Read(Null& null, std::istream& istr) { Read_i(null, istr); }
+inline void Reader::Read(UnknownElement& unknown, std::istream& istr) { Read_i(unknown, istr); }
+
+
+template <typename ElementTypeT>
+void Reader::Read_i(ElementTypeT& element, std::istream& istr)
+{
+ Reader reader;
+
+ Tokens tokens;
+ InputStream inputStream(istr);
+ reader.Scan(tokens, inputStream);
+
+ TokenStream tokenStream(tokens);
+ reader.Parse(element, tokenStream);
+
+ if (tokenStream.EOS() == false)
+ {
+ const Token& token = tokenStream.Peek();
+ std::string sMessage = std::string("Expected End of token stream; found ") + token.sValue;
+ throw ParseException(sMessage, token.locBegin, token.locEnd);
+ }
+}
+
+
+inline void Reader::Scan(Tokens& tokens, InputStream& inputStream)
+{
+ while (EatWhiteSpace(inputStream), // ignore any leading white space...
+ inputStream.EOS() == false) // ...before checking for EOS
+ {
+ // if all goes well, we'll create a token each pass
+ Token token;
+ token.locBegin = inputStream.GetLocation();
+
+ // gives us null-terminated string
+ char sChar = inputStream.Peek();
+ switch (sChar)
+ {
+ case '{':
+ token.sValue = MatchExpectedString(inputStream, "{");
+ token.nType = Token::TOKEN_OBJECT_BEGIN;
+ break;
+
+ case '}':
+ token.sValue = MatchExpectedString(inputStream, "}");
+ token.nType = Token::TOKEN_OBJECT_END;
+ break;
+
+ case '[':
+ token.sValue = MatchExpectedString(inputStream, "[");
+ token.nType = Token::TOKEN_ARRAY_BEGIN;
+ break;
+
+ case ']':
+ token.sValue = MatchExpectedString(inputStream, "]");
+ token.nType = Token::TOKEN_ARRAY_END;
+ break;
+
+ case ',':
+ token.sValue = MatchExpectedString(inputStream, ",");
+ token.nType = Token::TOKEN_NEXT_ELEMENT;
+ break;
+
+ case ':':
+ token.sValue = MatchExpectedString(inputStream, ":");
+ token.nType = Token::TOKEN_MEMBER_ASSIGN;
+ break;
+
+ case '"':
+ token.sValue = MatchString(inputStream);
+ token.nType = Token::TOKEN_STRING;
+ break;
+
+ case '-':
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9':
+ token.sValue = MatchNumber(inputStream);
+ token.nType = Token::TOKEN_NUMBER;
+ break;
+
+ case 't':
+ token.sValue = MatchExpectedString(inputStream, "true");
+ token.nType = Token::TOKEN_BOOLEAN;
+ break;
+
+ case 'f':
+ token.sValue = MatchExpectedString(inputStream, "false");
+ token.nType = Token::TOKEN_BOOLEAN;
+ break;
+
+ case 'n':
+ token.sValue = MatchExpectedString(inputStream, "null");
+ token.nType = Token::TOKEN_NULL;
+ break;
+
+ default:
+ {
+ std::string sErrorMessage = std::string("Unexpected character in stream: ") + sChar;
+ throw ScanException(sErrorMessage, inputStream.GetLocation());
+ }
+ }
+
+ token.locEnd = inputStream.GetLocation();
+ tokens.push_back(token);
+ }
+}
+
+
+inline void Reader::EatWhiteSpace(InputStream& inputStream)
+{
+ while (inputStream.EOS() == false &&
+ ::isspace(inputStream.Peek()))
+ inputStream.Get();
+}
+
+inline std::string Reader::MatchExpectedString(InputStream& inputStream, const std::string& sExpected)
+{
+ std::string::const_iterator it(sExpected.begin()),
+ itEnd(sExpected.end());
+ for ( ; it != itEnd; ++it) {
+ if (inputStream.EOS() || // did we reach the end before finding what we're looking for...
+ inputStream.Get() != *it) // ...or did we find something different?
+ {
+ std::string sMessage = std::string("Expected string: ") + sExpected;
+ throw ScanException(sMessage, inputStream.GetLocation());
+ }
+ }
+
+ // all's well if we made it here
+ return sExpected;
+}
+
+
+inline std::string Reader::MatchString(InputStream& inputStream)
+{
+ MatchExpectedString(inputStream, "\"");
+
+ std::string string;
+ while (inputStream.EOS() == false &&
+ inputStream.Peek() != '"')
+ {
+ char c = inputStream.Get();
+
+ // escape?
+ if (c == '\\' &&
+ inputStream.EOS() == false) // shouldn't have reached the end yet
+ {
+ c = inputStream.Get();
+ switch (c) {
+ case '/': string.push_back('/'); break;
+ case '"': string.push_back('"'); break;
+ case '\\': string.push_back('\\'); break;
+ case 'b': string.push_back('\b'); break;
+ case 'f': string.push_back('\f'); break;
+ case 'n': string.push_back('\n'); break;
+ case 'r': string.push_back('\r'); break;
+ case 't': string.push_back('\t'); break;
+ //case 'u': string.push_back('\u'); break; // TODO: what do we do with this?
+ default: {
+ std::string sMessage = std::string("Unrecognized escape sequence found in string: \\") + c;
+ throw ScanException(sMessage, inputStream.GetLocation());
+ }
+ }
+ }
+ else {
+ string.push_back(c);
+ }
+ }
+
+ // eat the last '"' that we just peeked
+ MatchExpectedString(inputStream, "\"");
+
+ // all's well if we made it here
+ return string;
+}
+
+
+inline std::string Reader::MatchNumber(InputStream& inputStream)
+{
+ const char sNumericChars[] = "0123456789.eE-+";
+ std::set<char> numericChars;
+ numericChars.insert(sNumericChars, sNumericChars + sizeof(sNumericChars));
+
+ std::string sNumber;
+ while (inputStream.EOS() == false &&
+ numericChars.find(inputStream.Peek()) != numericChars.end())
+ {
+ sNumber.push_back(inputStream.Get());
+ }
+
+ return sNumber;
+}
+
+
+inline void Reader::Parse(UnknownElement& element, Reader::TokenStream& tokenStream)
+{
+ const Token& token = tokenStream.Peek();
+ switch (token.nType) {
+ case Token::TOKEN_OBJECT_BEGIN:
+ {
+ // implicit non-const cast will perform conversion for us (if necessary)
+ Object& object = element;
+ Parse(object, tokenStream);
+ break;
+ }
+
+ case Token::TOKEN_ARRAY_BEGIN:
+ {
+ Array& array = element;
+ Parse(array, tokenStream);
+ break;
+ }
+
+ case Token::TOKEN_STRING:
+ {
+ String& string = element;
+ Parse(string, tokenStream);
+ break;
+ }
+
+ case Token::TOKEN_NUMBER:
+ {
+ Number& number = element;
+ Parse(number, tokenStream);
+ break;
+ }
+
+ case Token::TOKEN_BOOLEAN:
+ {
+ Boolean& boolean = element;
+ Parse(boolean, tokenStream);
+ break;
+ }
+
+ case Token::TOKEN_NULL:
+ {
+ Null& null = element;
+ Parse(null, tokenStream);
+ break;
+ }
+
+ default:
+ {
+ std::string sMessage = std::string("Unexpected token: ") + token.sValue;
+ throw ParseException(sMessage, token.locBegin, token.locEnd);
+ }
+ }
+}
+
+
+inline void Reader::Parse(Object& object, Reader::TokenStream& tokenStream)
+{
+ MatchExpectedToken(Token::TOKEN_OBJECT_BEGIN, tokenStream);
+
+ bool bContinue = (tokenStream.EOS() == false &&
+ tokenStream.Peek().nType != Token::TOKEN_OBJECT_END);
+ while (bContinue)
+ {
+ Object::Member member;
+
+ // first the member name. save the token in case we have to throw an exception
+ const Token& tokenName = tokenStream.Peek();
+ member.name = MatchExpectedToken(Token::TOKEN_STRING, tokenStream);
+
+ // ...then the key/value separator...
+ MatchExpectedToken(Token::TOKEN_MEMBER_ASSIGN, tokenStream);
+
+ // ...then the value itself (can be anything).
+ Parse(member.element, tokenStream);
+
+ // try adding it to the object (this could throw)
+ try
+ {
+ object.Insert(member);
+ }
+ catch (Exception&)
+ {
+ // must be a duplicate name
+ std::string sMessage = std::string("Duplicate object member token: ") + member.name;
+ throw ParseException(sMessage, tokenName.locBegin, tokenName.locEnd);
+ }
+
+ bContinue = (tokenStream.EOS() == false &&
+ tokenStream.Peek().nType == Token::TOKEN_NEXT_ELEMENT);
+ if (bContinue)
+ MatchExpectedToken(Token::TOKEN_NEXT_ELEMENT, tokenStream);
+ }
+
+ MatchExpectedToken(Token::TOKEN_OBJECT_END, tokenStream);
+}
+
+
+inline void Reader::Parse(Array& array, Reader::TokenStream& tokenStream)
+{
+ MatchExpectedToken(Token::TOKEN_ARRAY_BEGIN, tokenStream);
+
+ bool bContinue = (tokenStream.EOS() == false &&
+ tokenStream.Peek().nType != Token::TOKEN_ARRAY_END);
+ while (bContinue)
+ {
+ // ...what's next? could be anything
+ Array::iterator itElement = array.Insert(UnknownElement());
+ UnknownElement& element = *itElement;
+ Parse(element, tokenStream);
+
+ bContinue = (tokenStream.EOS() == false &&
+ tokenStream.Peek().nType == Token::TOKEN_NEXT_ELEMENT);
+ if (bContinue)
+ MatchExpectedToken(Token::TOKEN_NEXT_ELEMENT, tokenStream);
+ }
+
+ MatchExpectedToken(Token::TOKEN_ARRAY_END, tokenStream);
+}
+
+
+inline void Reader::Parse(String& string, Reader::TokenStream& tokenStream)
+{
+ string = MatchExpectedToken(Token::TOKEN_STRING, tokenStream);
+}
+
+
+inline void Reader::Parse(Number& number, Reader::TokenStream& tokenStream)
+{
+ const Token& currentToken = tokenStream.Peek(); // might need this later for throwing exception
+ const std::string& sValue = MatchExpectedToken(Token::TOKEN_NUMBER, tokenStream);
+
+ std::istringstream iStr(sValue);
+ double dValue;
+ iStr >> dValue;
+
+ // did we consume all characters in the token?
+ if (iStr.eof() == false)
+ {
+ char c = iStr.peek();
+ std::string sMessage = std::string("Unexpected character in NUMBER token: ") + c;
+ throw ParseException(sMessage, currentToken.locBegin, currentToken.locEnd);
+ }
+
+ number = dValue;
+}
+
+
+inline void Reader::Parse(Boolean& boolean, Reader::TokenStream& tokenStream)
+{
+ const std::string& sValue = MatchExpectedToken(Token::TOKEN_BOOLEAN, tokenStream);
+ boolean = (sValue == "true" ? true : false);
+}
+
+
+inline void Reader::Parse(Null&, Reader::TokenStream& tokenStream)
+{
+ MatchExpectedToken(Token::TOKEN_NULL, tokenStream);
+}
+
+
+inline const std::string& Reader::MatchExpectedToken(Token::Type nExpected, Reader::TokenStream& tokenStream)
+{
+ const Token& token = tokenStream.Get();
+ if (token.nType != nExpected)
+ {
+ std::string sMessage = std::string("Unexpected token: ") + token.sValue;
+ throw ParseException(sMessage, token.locBegin, token.locEnd);
+ }
+
+ return token.sValue;
+}
+
+} // End namespace
Property changes on: rutil/cajun/json/reader.inl
___________________________________________________________________
Added: svn:eol-style
+ native
Index: rutil/cajun/json/visitor.h
===================================================================
--- rutil/cajun/json/visitor.h (.../branches/resiprocate-1.8) (revision 0)
+++ rutil/cajun/json/visitor.h (.../main) (revision 9855)
@@ -0,0 +1,65 @@
+/******************************************************************************
+
+Copyright (c) 2009-2010, Terry Caton
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+ * Neither the name of the projecct nor the names of its contributors
+ may be used to endorse or promote products derived from this software
+ without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+******************************************************************************/
+
+#pragma once
+
+#include "elements.h"
+
+namespace json
+{
+
+
+class Visitor
+{
+public:
+ virtual ~Visitor() {}
+
+ virtual void Visit(Array& array) = 0;
+ virtual void Visit(Object& object) = 0;
+ virtual void Visit(Number& number) = 0;
+ virtual void Visit(String& string) = 0;
+ virtual void Visit(Boolean& boolean) = 0;
+ virtual void Visit(Null& null) = 0;
+};
+
+class ConstVisitor
+{
+public:
+ virtual ~ConstVisitor() {}
+
+ virtual void Visit(const Array& array) = 0;
+ virtual void Visit(const Object& object) = 0;
+ virtual void Visit(const Number& number) = 0;
+ virtual void Visit(const String& string) = 0;
+ virtual void Visit(const Boolean& boolean) = 0;
+ virtual void Visit(const Null& null) = 0;
+};
+
+
+} // End namespace
Property changes on: rutil/cajun/json/visitor.h
___________________________________________________________________
Added: svn:eol-style
+ native
Index: rutil/cajun/json/reader.h
===================================================================
--- rutil/cajun/json/reader.h (.../branches/resiprocate-1.8) (revision 0)
+++ rutil/cajun/json/reader.h (.../main) (revision 9855)
@@ -0,0 +1,148 @@
+/******************************************************************************
+
+Copyright (c) 2009-2010, Terry Caton
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+ * Neither the name of the projecct nor the names of its contributors
+ may be used to endorse or promote products derived from this software
+ without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+******************************************************************************/
+
+
+
+#pragma once
+
+#include "elements.h"
+#include <iostream>
+#include <vector>
+
+namespace json
+{
+
+class Reader
+{
+public:
+ // this structure will be reported in one of the exceptions defined below
+ struct Location
+ {
+ Location();
+
+ unsigned int m_nLine; // document line, zero-indexed
+ unsigned int m_nLineOffset; // character offset from beginning of line, zero indexed
+ unsigned int m_nDocOffset; // character offset from entire document, zero indexed
+ };
+
+ // thrown during the first phase of reading. generally catches low-level problems such
+ // as errant characters or corrupt/incomplete documents
+ class ScanException : public Exception
+ {
+ public:
+ ScanException(const std::string& sMessage, const Reader::Location& locError) :
+ Exception(sMessage),
+ m_locError(locError) {}
+
+ Reader::Location m_locError;
+ };
+
+ // thrown during the second phase of reading. generally catches higher-level problems such
+ // as missing commas or brackets
+ class ParseException : public Exception
+ {
+ public:
+ ParseException(const std::string& sMessage, const Reader::Location& locTokenBegin, const Reader::Location& locTokenEnd) :
+ Exception(sMessage),
+ m_locTokenBegin(locTokenBegin),
+ m_locTokenEnd(locTokenEnd) {}
+
+ Reader::Location m_locTokenBegin;
+ Reader::Location m_locTokenEnd;
+ };
+
+
+ // if you know what the document looks like, call one of these...
+ static void Read(Object& object, std::istream& istr);
+ static void Read(Array& array, std::istream& istr);
+ static void Read(String& string, std::istream& istr);
+ static void Read(Number& number, std::istream& istr);
+ static void Read(Boolean& boolean, std::istream& istr);
+ static void Read(Null& null, std::istream& istr);
+
+ // ...otherwise, if you don't know, call this & visit it
+ static void Read(UnknownElement& elementRoot, std::istream& istr);
+
+private:
+ struct Token
+ {
+ enum Type
+ {
+ TOKEN_OBJECT_BEGIN, // {
+ TOKEN_OBJECT_END, // }
+ TOKEN_ARRAY_BEGIN, // [
+ TOKEN_ARRAY_END, // ]
+ TOKEN_NEXT_ELEMENT, // ,
+ TOKEN_MEMBER_ASSIGN, // :
+ TOKEN_STRING, // "xxx"
+ TOKEN_NUMBER, // [+/-]000.000[e[+/-]000]
+ TOKEN_BOOLEAN, // true -or- false
+ TOKEN_NULL, // null
+ };
+
+ Type nType;
+ std::string sValue;
+
+ // for malformed file debugging
+ Reader::Location locBegin;
+ Reader::Location locEnd;
+ };
+
+ class InputStream;
+ class TokenStream;
+ typedef std::vector<Token> Tokens;
+
+ template <typename ElementTypeT>
+ static void Read_i(ElementTypeT& element, std::istream& istr);
+
+ // scanning istream into token sequence
+ void Scan(Tokens& tokens, InputStream& inputStream);
+
+ void EatWhiteSpace(InputStream& inputStream);
+ std::string MatchString(InputStream& inputStream);
+ std::string MatchNumber(InputStream& inputStream);
+ std::string MatchExpectedString(InputStream& inputStream, const std::string& sExpected);
+
+ // parsing token sequence into element structure
+ void Parse(UnknownElement& element, TokenStream& tokenStream);
+ void Parse(Object& object, TokenStream& tokenStream);
+ void Parse(Array& array, TokenStream& tokenStream);
+ void Parse(String& string, TokenStream& tokenStream);
+ void Parse(Number& number, TokenStream& tokenStream);
+ void Parse(Boolean& boolean, TokenStream& tokenStream);
+ void Parse(Null& null, TokenStream& tokenStream);
+
+ const std::string& MatchExpectedToken(Token::Type nExpected, TokenStream& tokenStream);
+};
+
+
+} // End namespace
+
+
+#include "reader.inl"
\ No newline at end of file
Property changes on: rutil/cajun/json/reader.h
___________________________________________________________________
Added: svn:eol-style
+ native
Index: rutil/cajun/json/elements.inl
===================================================================
--- rutil/cajun/json/elements.inl (.../branches/resiprocate-1.8) (revision 0)
+++ rutil/cajun/json/elements.inl (.../main) (revision 9855)
@@ -0,0 +1,442 @@
+/******************************************************************************
+
+Copyright (c) 2009-2010, Terry Caton
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+ * Neither the name of the projecct nor the names of its contributors
+ may be used to endorse or promote products derived from this software
+ without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+******************************************************************************/
+
+#include "visitor.h"
+#include "reader.h"
+#include <cassert>
+#include <algorithm>
+#include <map>
+
+/*
+
+TODO:
+* better documentation
+
+*/
+
+namespace json
+{
+
+
+inline Exception::Exception(const std::string& sMessage) :
+ std::runtime_error(sMessage) {}
+
+
+/////////////////////////
+// UnknownElement members
+
+class UnknownElement::Imp
+{
+public:
+ virtual ~Imp() {}
+ virtual Imp* Clone() const = 0;
+
+ virtual bool Compare(const Imp& imp) const = 0;
+
+ virtual void Accept(ConstVisitor& visitor) const = 0;
+ virtual void Accept(Visitor& visitor) = 0;
+};
+
+
+template <typename ElementTypeT>
+class UnknownElement::Imp_T : public UnknownElement::Imp
+{
+public:
+ Imp_T(const ElementTypeT& element) : m_Element(element) {}
+ virtual Imp* Clone() const { return new Imp_T<ElementTypeT>(*this); }
+
+ virtual void Accept(ConstVisitor& visitor) const { visitor.Visit(m_Element); }
+ virtual void Accept(Visitor& visitor) { visitor.Visit(m_Element); }
+
+ virtual bool Compare(const Imp& imp) const
+ {
+ ConstCastVisitor_T<ElementTypeT> castVisitor;
+ imp.Accept(castVisitor);
+ return castVisitor.m_pElement &&
+ m_Element == *castVisitor.m_pElement;
+ }
+
+private:
+ ElementTypeT m_Element;
+};
+
+
+class UnknownElement::ConstCastVisitor : public ConstVisitor
+{
+ virtual void Visit(const Array& array) {}
+ virtual void Visit(const Object& object) {}
+ virtual void Visit(const Number& number) {}
+ virtual void Visit(const String& string) {}
+ virtual void Visit(const Boolean& boolean) {}
+ virtual void Visit(const Null& null) {}
+};
+
+template <typename ElementTypeT>
+class UnknownElement::ConstCastVisitor_T : public ConstCastVisitor
+{
+public:
+ ConstCastVisitor_T() : m_pElement(0) {}
+ virtual void Visit(const ElementTypeT& element) { m_pElement = &element; } // we don't know what this is, but it overrides one of the base's no-op functions
+ const ElementTypeT* m_pElement;
+};
+
+
+class UnknownElement::CastVisitor : public Visitor
+{
+ virtual void Visit(Array& array) {}
+ virtual void Visit(Object& object) {}
+ virtual void Visit(Number& number) {}
+ virtual void Visit(String& string) {}
+ virtual void Visit(Boolean& boolean) {}
+ virtual void Visit(Null& null) {}
+};
+
+template <typename ElementTypeT>
+class UnknownElement::CastVisitor_T : public CastVisitor
+{
+public:
+ CastVisitor_T() : m_pElement(0) {}
+ virtual void Visit(ElementTypeT& element) { m_pElement = &element; } // we don't know what this is, but it overrides one of the base's no-op functions
+ ElementTypeT* m_pElement;
+};
+
+
+
+
+inline UnknownElement::UnknownElement() : m_pImp( new Imp_T<Null>( Null() ) ) {}
+inline UnknownElement::UnknownElement(const UnknownElement& unknown) : m_pImp( unknown.m_pImp->Clone()) {}
+inline UnknownElement::UnknownElement(const Object& object) : m_pImp( new Imp_T<Object>(object) ) {}
+inline UnknownElement::UnknownElement(const Array& array) : m_pImp( new Imp_T<Array>(array) ) {}
+inline UnknownElement::UnknownElement(const Number& number) : m_pImp( new Imp_T<Number>(number) ) {}
+inline UnknownElement::UnknownElement(const Boolean& boolean) : m_pImp( new Imp_T<Boolean>(boolean) ) {}
+inline UnknownElement::UnknownElement(const String& string) : m_pImp( new Imp_T<String>(string) ) {}
+inline UnknownElement::UnknownElement(const Null& null) : m_pImp( new Imp_T<Null>(null) ) {}
+
+inline UnknownElement::~UnknownElement() { delete m_pImp; }
+
+inline UnknownElement::operator const Object& () const { return CastTo<Object>(); }
+inline UnknownElement::operator const Array& () const { return CastTo<Array>(); }
+inline UnknownElement::operator const Number& () const { return CastTo<Number>(); }
+inline UnknownElement::operator const Boolean& () const { return CastTo<Boolean>(); }
+inline UnknownElement::operator const String& () const { return CastTo<String>(); }
+inline UnknownElement::operator const Null& () const { return CastTo<Null>(); }
+
+inline UnknownElement::operator Object& () { return ConvertTo<Object>(); }
+inline UnknownElement::operator Array& () { return ConvertTo<Array>(); }
+inline UnknownElement::operator Number& () { return ConvertTo<Number>(); }
+inline UnknownElement::operator Boolean& () { return ConvertTo<Boolean>(); }
+inline UnknownElement::operator String& () { return ConvertTo<String>(); }
+inline UnknownElement::operator Null& () { return ConvertTo<Null>(); }
+
+inline UnknownElement& UnknownElement::operator = (const UnknownElement& unknown)
+{
+ // always check for this
+ if (&unknown != this)
+ {
+ // we might be copying from a subtree of ourselves. delete the old imp
+ // only after the clone operation is complete. yes, this could be made
+ // more efficient, but isn't worth the complexity
+ Imp* pOldImp = m_pImp;
+ m_pImp = unknown.m_pImp->Clone();
+ delete pOldImp;
+ }
+
+ return *this;
+}
+
+inline UnknownElement& UnknownElement::operator[] (const std::string& key)
+{
+ // the people want an object. make us one if we aren't already
+ Object& object = ConvertTo<Object>();
+ return object[key];
+}
+
+inline const UnknownElement& UnknownElement::operator[] (const std::string& key) const
+{
+ // throws if we aren't an object
+ const Object& object = CastTo<Object>();
+ return object[key];
+}
+
+inline UnknownElement& UnknownElement::operator[] (size_t index)
+{
+ // the people want an array. make us one if we aren't already
+ Array& array = ConvertTo<Array>();
+ return array[index];
+}
+
+inline const UnknownElement& UnknownElement::operator[] (size_t index) const
+{
+ // throws if we aren't an array
+ const Array& array = CastTo<Array>();
+ return array[index];
+}
+
+
+template <typename ElementTypeT>
+const ElementTypeT& UnknownElement::CastTo() const
+{
+ ConstCastVisitor_T<ElementTypeT> castVisitor;
+ m_pImp->Accept(castVisitor);
+ if (castVisitor.m_pElement == 0)
+ throw Exception("Bad cast");
+ return *castVisitor.m_pElement;
+}
+
+
+
+template <typename ElementTypeT>
+ElementTypeT& UnknownElement::ConvertTo()
+{
+ CastVisitor_T<ElementTypeT> castVisitor;
+ m_pImp->Accept(castVisitor);
+ if (castVisitor.m_pElement == 0)
+ {
+ // we're not the right type. fix it & try again
+ *this = ElementTypeT();
+ m_pImp->Accept(castVisitor);
+ }
+
+ return *castVisitor.m_pElement;
+}
+
+
+inline void UnknownElement::Accept(ConstVisitor& visitor) const { m_pImp->Accept(visitor); }
+inline void UnknownElement::Accept(Visitor& visitor) { m_pImp->Accept(visitor); }
+
+
+inline bool UnknownElement::operator == (const UnknownElement& element) const
+{
+ return m_pImp->Compare(*element.m_pImp);
+}
+
+
+
+//////////////////
+// Object members
+
+
+inline Object::Member::Member(const std::string& nameIn, const UnknownElement& elementIn) :
+ name(nameIn), element(elementIn) {}
+
+inline bool Object::Member::operator == (const Member& member) const
+{
+ return name == member.name &&
+ element == member.element;
+}
+
+class Object::Finder : public std::unary_function<Object::Member, bool>
+{
+public:
+ Finder(const std::string& name) : m_name(name) {}
+ bool operator () (const Object::Member& member) {
+ return member.name == m_name;
+ }
+
+private:
+ std::string m_name;
+};
+
+
+
+inline Object::iterator Object::Begin() { return m_Members.begin(); }
+inline Object::iterator Object::End() { return m_Members.end(); }
+inline Object::const_iterator Object::Begin() const { return m_Members.begin(); }
+inline Object::const_iterator Object::End() const { return m_Members.end(); }
+
+inline size_t Object::Size() const { return m_Members.size(); }
+inline bool Object::Empty() const { return m_Members.empty(); }
+
+inline Object::iterator Object::Find(const std::string& name)
+{
+ return std::find_if(m_Members.begin(), m_Members.end(), Finder(name));
+}
+
+inline Object::const_iterator Object::Find(const std::string& name) const
+{
+ return std::find_if(m_Members.begin(), m_Members.end(), Finder(name));
+}
+
+inline Object::iterator Object::Insert(const Member& member)
+{
+ return Insert(member, End());
+}
+
+inline Object::iterator Object::Insert(const Member& member, iterator itWhere)
+{
+ iterator it = Find(member.name);
+ if (it != m_Members.end())
+ throw Exception(std::string("Object member already exists: ") + member.name);
+
+ it = m_Members.insert(itWhere, member);
+ return it;
+}
+
+inline Object::iterator Object::Erase(iterator itWhere)
+{
+ return m_Members.erase(itWhere);
+}
+
+inline UnknownElement& Object::operator [](const std::string& name)
+{
+
+ iterator it = Find(name);
+ if (it == m_Members.end())
+ {
+ Member member(name);
+ it = Insert(member, End());
+ }
+ return it->element;
+}
+
+inline const UnknownElement& Object::operator [](const std::string& name) const
+{
+ const_iterator it = Find(name);
+ if (it == End())
+ throw Exception(std::string("Object member not found: ") + name);
+ return it->element;
+}
+
+inline void Object::Clear()
+{
+ m_Members.clear();
+}
+
+inline bool Object::operator == (const Object& object) const
+{
+ return m_Members == object.m_Members;
+}
+
+
+/////////////////
+// Array members
+
+inline Array::iterator Array::Begin() { return m_Elements.begin(); }
+inline Array::iterator Array::End() { return m_Elements.end(); }
+inline Array::const_iterator Array::Begin() const { return m_Elements.begin(); }
+inline Array::const_iterator Array::End() const { return m_Elements.end(); }
+
+inline Array::iterator Array::Insert(const UnknownElement& element, iterator itWhere)
+{
+ return m_Elements.insert(itWhere, element);
+}
+
+inline Array::iterator Array::Insert(const UnknownElement& element)
+{
+ return Insert(element, End());
+}
+
+inline Array::iterator Array::Erase(iterator itWhere)
+{
+ return m_Elements.erase(itWhere);
+}
+
+inline void Array::Resize(size_t newSize)
+{
+ m_Elements.resize(newSize);
+}
+
+inline size_t Array::Size() const { return m_Elements.size(); }
+inline bool Array::Empty() const { return m_Elements.empty(); }
+
+inline UnknownElement& Array::operator[] (size_t index)
+{
+ size_t nMinSize = index + 1; // zero indexed
+ if (m_Elements.size() < nMinSize)
+ m_Elements.resize(nMinSize);
+ return m_Elements[index];
+}
+
+inline const UnknownElement& Array::operator[] (size_t index) const
+{
+ if (index >= m_Elements.size())
+ throw Exception("Array out of bounds");
+ return m_Elements[index];
+}
+
+inline void Array::Clear() {
+ m_Elements.clear();
+}
+
+inline bool Array::operator == (const Array& array) const
+{
+ return m_Elements == array.m_Elements;
+}
+
+
+////////////////////////
+// TrivialType_T members
+
+template <typename DataTypeT>
+TrivialType_T<DataTypeT>::TrivialType_T(const DataTypeT& t) :
+ m_tValue(t) {}
+
+template <typename DataTypeT>
+TrivialType_T<DataTypeT>::operator DataTypeT&()
+{
+ return Value();
+}
+
+template <typename DataTypeT>
+TrivialType_T<DataTypeT>::operator const DataTypeT&() const
+{
+ return Value();
+}
+
+template <typename DataTypeT>
+DataTypeT& TrivialType_T<DataTypeT>::Value()
+{
+ return m_tValue;
+}
+
+template <typename DataTypeT>
+const DataTypeT& TrivialType_T<DataTypeT>::Value() const
+{
+ return m_tValue;
+}
+
+template <typename DataTypeT>
+bool TrivialType_T<DataTypeT>::operator == (const TrivialType_T<DataTypeT>& trivial) const
+{
+ return m_tValue == trivial.m_tValue;
+}
+
+
+
+//////////////////
+// Null members
+
+inline bool Null::operator == (const Null& trivial) const
+{
+ return true;
+}
+
+
+
+} // End namespace
Property changes on: rutil/cajun/json/elements.inl
___________________________________________________________________
Added: svn:eol-style
+ native
Index: rutil/cajun/json/writer.inl
===================================================================
--- rutil/cajun/json/writer.inl (.../branches/resiprocate-1.8) (revision 0)
+++ rutil/cajun/json/writer.inl (.../main) (revision 9855)
@@ -0,0 +1,178 @@
+/******************************************************************************
+
+Copyright (c) 2009-2010, Terry Caton
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+ * Neither the name of the projecct nor the names of its contributors
+ may be used to endorse or promote products derived from this software
+ without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+******************************************************************************/
+
+#include "writer.h"
+#include <iostream>
+#include <iomanip>
+
+/*
+
+TODO:
+* better documentation
+* unicode character encoding
+
+*/
+
+namespace json
+{
+
+
+inline void Writer::Write(const UnknownElement& elementRoot, std::ostream& ostr) { Write_i(elementRoot, ostr); }
+inline void Writer::Write(const Object& object, std::ostream& ostr) { Write_i(object, ostr); }
+inline void Writer::Write(const Array& array, std::ostream& ostr) { Write_i(array, ostr); }
+inline void Writer::Write(const Number& number, std::ostream& ostr) { Write_i(number, ostr); }
+inline void Writer::Write(const String& string, std::ostream& ostr) { Write_i(string, ostr); }
+inline void Writer::Write(const Boolean& boolean, std::ostream& ostr) { Write_i(boolean, ostr); }
+inline void Writer::Write(const Null& null, std::ostream& ostr) { Write_i(null, ostr); }
+
+
+inline Writer::Writer(std::ostream& ostr) :
+ m_ostr(ostr),
+ m_nTabDepth(0)
+{}
+
+template <typename ElementTypeT>
+void Writer::Write_i(const ElementTypeT& element, std::ostream& ostr)
+{
+ Writer writer(ostr);
+ writer.Write_i(element);
+ ostr.flush(); // all done
+}
+
+inline void Writer::Write_i(const Array& array)
+{
+ if (array.Empty())
+ m_ostr << "[]";
+ else
+ {
+ m_ostr << '[' << std::endl;
+ ++m_nTabDepth;
+
+ Array::const_iterator it(array.Begin()),
+ itEnd(array.End());
+ while (it != itEnd) {
+ m_ostr << std::string(m_nTabDepth, '\t');
+
+ Write_i(*it);
+
+ if (++it != itEnd)
+ m_ostr << ',';
+ m_ostr << std::endl;
+ }
+
+ --m_nTabDepth;
+ m_ostr << std::string(m_nTabDepth, '\t') << ']';
+ }
+}
+
+inline void Writer::Write_i(const Object& object)
+{
+ if (object.Empty())
+ m_ostr << "{}";
+ else
+ {
+ m_ostr << '{' << std::endl;
+ ++m_nTabDepth;
+
+ Object::const_iterator it(object.Begin()),
+ itEnd(object.End());
+ while (it != itEnd) {
+ m_ostr << std::string(m_nTabDepth, '\t');
+
+ Write_i(it->name);
+
+ m_ostr << " : ";
+ Write_i(it->element);
+
+ if (++it != itEnd)
+ m_ostr << ',';
+ m_ostr << std::endl;
+ }
+
+ --m_nTabDepth;
+ m_ostr << std::string(m_nTabDepth, '\t') << '}';
+ }
+}
+
+inline void Writer::Write_i(const Number& numberElement)
+{
+ m_ostr << std::setprecision(20) << numberElement.Value();
+}
+
+inline void Writer::Write_i(const Boolean& booleanElement)
+{
+ m_ostr << (booleanElement.Value() ? "true" : "false");
+}
+
+inline void Writer::Write_i(const String& stringElement)
+{
+ m_ostr << '"';
+
+ const std::string& s = stringElement.Value();
+ std::string::const_iterator it(s.begin()),
+ itEnd(s.end());
+ for (; it != itEnd; ++it)
+ {
+ switch (*it)
+ {
+ case '"': m_ostr << "\\\""; break;
+ case '\\': m_ostr << "\\\\"; break;
+ case '\b': m_ostr << "\\b"; break;
+ case '\f': m_ostr << "\\f"; break;
+ case '\n': m_ostr << "\\n"; break;
+ case '\r': m_ostr << "\\r"; break;
+ case '\t': m_ostr << "\\t"; break;
+ //case '\u': m_ostr << "\\u"; break; // uh...
+ default: m_ostr << *it; break;
+ }
+ }
+
+ m_ostr << '"';
+}
+
+inline void Writer::Write_i(const Null& )
+{
+ m_ostr << "null";
+}
+
+inline void Writer::Write_i(const UnknownElement& unknown)
+{
+ unknown.Accept(*this);
+}
+
+inline void Writer::Visit(const Array& array) { Write_i(array); }
+inline void Writer::Visit(const Object& object) { Write_i(object); }
+inline void Writer::Visit(const Number& number) { Write_i(number); }
+inline void Writer::Visit(const String& string) { Write_i(string); }
+inline void Writer::Visit(const Boolean& boolean) { Write_i(boolean); }
+inline void Writer::Visit(const Null& null) { Write_i(null); }
+
+
+
+} // End namespace
Property changes on: rutil/cajun/json/writer.inl
___________________________________________________________________
Added: svn:eol-style
+ native
Index: rutil/cajun/Readme.txt
===================================================================
--- rutil/cajun/Readme.txt (.../branches/resiprocate-1.8) (revision 0)
+++ rutil/cajun/Readme.txt (.../main) (revision 9855)
@@ -0,0 +1,14 @@
+CAJUN* is a C++ API for the JSON object interchange format. JSON is like XML, except it doesn't suck**. It is specifically designed for representing (in plain text format) structures familiar to software engineers: booleans, numerics, strings, arrays, and objects (i.e. name/value pairs, associative array, etc.); it humbly leaves text markup to XML. It is ideal for storing persistent application data, such as configuration or user data files.
+
+Too many JSON parsers I've seen suffer from overly complex designs and confusing interfaces, so in true software engineer form, I thought I could do better. The goal of JSON was to create an simple, "minimalist" interface while sacrificing absolutely no power or flexibility. The STL containers, while not without their violations of that spirit, served as an inspiration. The end result is (IMHO) an interface that should be immediately intuitive to anyone familiar with C++ and the Standard Library containers. It can best be described as working with an "element", where an element may consist of:
+* String (mimics std::string)
+* Numeric (double)
+* Boolean (bool)
+* Array (std::vector<UnknownElement>)
+* Object (unsorted std::map<std::string, UnknownElement>)
+* UnknownElement - like boost::any, but restricted to types below. Used to aggregate elements within Objects & Arrays, and for reading documents of unknown structure
+
+As with any design, sacrifices were made with CAJUN. Most situations I've encountered where JSON is well-suited (reading & writing application configuration and data files) are not typically performance bottlenecks, so simplicity, safety & flexibility were favored over raw speed. The end result is a library with simple, typesafe classes, no memory-management burden on the user, and exception-based error reporting.
+
+* C++ API for JSON. A pint on me for who ever comes up with a good meaning for "UN".
+** To be fair, XML doesn't suck intentionally, it is just often used inappropriately.
\ No newline at end of file
Property changes on: rutil/cajun/Readme.txt
___________________________________________________________________
Added: svn:eol-style
+ native
Index: rutil/TimeLimitFifo.hxx
===================================================================
--- rutil/TimeLimitFifo.hxx (.../branches/resiprocate-1.8) (revision 9855)
+++ rutil/TimeLimitFifo.hxx (.../main) (revision 9855)
@@ -94,7 +94,7 @@
typedef enum {EnforceTimeDepth, IgnoreTimeDepth, InternalElement} DepthUsage;
/// After it runs out of the lesser of these limits it will start to refuse messages
- TimeLimitFifo(unsigned int maxDurationSecs,
+ TimeLimitFifo(unsigned int maxDurationSecs,
unsigned int maxSize);
virtual ~TimeLimitFifo();
@@ -108,24 +108,24 @@
/// @brief Add a message to the fifo.
/// return true iff succeeds
- /// @param Msg* 'Message pointer'
+ /// @param Msg* 'Message pointer'
/// @param DepthUsage : (Needs work...)
/// EnforceTimeDepth -- external (non ACK) requests
/// IgnoreTimeDepth -- external reponse and ACK
/// InternalElement -- internal messages (timers, application postbacks..); use reserved queue space
///
- /// +------------------------------------------------------+
- /// | | | |
- /// +------------------------------------------------------+
- /// <-----enforce------------------->
- /// <---------------ignoreTimeDepth------------>
- /// <--------------------- internalElement---------------->
- ///
- /// enforce will drop things that exceed the queue
- /// ignore will go past that limit to the extent of the queue (eg.
- /// internal will basically not drop anything
- ///
- bool add(Msg* msg, DepthUsage usage);
+ /// +------------------------------------------------------+
+ /// | | | |
+ /// +------------------------------------------------------+
+ /// <-----enforce------------------->
+ /// <---------------ignoreTimeDepth------------>
+ /// <--------------------- internalElement---------------->
+ ///
+ /// enforce will drop things that exceed the queue
+ /// ignore will go past that limit to the extent of the queue (eg.
+ /// internal will basically not drop anything
+ ///
+ bool add(Msg* msg, DepthUsage usage);
/**
@brief Returns the first message available.
Index: rutil/WinCompat.hxx
===================================================================
--- rutil/WinCompat.hxx (.../branches/resiprocate-1.8) (revision 9855)
+++ rutil/WinCompat.hxx (.../main) (revision 9855)
@@ -57,6 +57,8 @@
typedef DWORD (WINAPI * GetBestInterfaceExProc)(const sockaddr *, DWORD *);
typedef DWORD (WINAPI * GetAdaptersAddressesProc)(ULONG, DWORD, VOID *, IP_ADAPTER_ADDRESSES *, ULONG *);
typedef DWORD (WINAPI * GetAdaptersInfoProc)(PIP_ADAPTER_INFO, PULONG);
+ typedef DWORD (WINAPI * GetBestRouteProc)(DWORD dwDestAddr, DWORD dwSourceAddr, PMIB_IPFORWARDROW pBestRoute);
+ typedef DWORD (WINAPI * GetIpAddrTableProc)(PMIB_IPADDRTABLE pIpAddrTable, PULONG pdwSize, BOOL bOrder);
WinCompat();
~WinCompat();
@@ -64,6 +66,8 @@
GetBestInterfaceExProc getBestInterfaceEx;
GetAdaptersAddressesProc getAdaptersAddresses;
GetAdaptersInfoProc getAdaptersInfo;
+ GetBestRouteProc getBestRoute;
+ GetIpAddrTableProc getIpAddrTable;
bool loadLibraryWithIPv4Failed;
bool loadLibraryWithIPv6Failed;
HMODULE hLib;
Index: rutil/FileSystem.cxx
===================================================================
--- rutil/FileSystem.cxx (.../branches/resiprocate-1.8) (revision 9855)
+++ rutil/FileSystem.cxx (.../main) (revision 9855)
@@ -105,9 +105,19 @@
{
return mDirent->d_type == DT_DIR;
}
+
+int
+FileSystem::Directory::create() const
+{
+ if(mkdir(mPath.c_str(), 0777) == -1)
+ {
+ return errno;
+ }
+ return 0;
+}
+
#else
-
FileSystem::Directory::iterator::iterator() :
mWinSearch(0)
{
@@ -209,6 +219,17 @@
{
return mIsDirectory;
}
+
+int
+FileSystem::Directory::create() const
+{
+ if(_mkdir(mPath.c_str()) == -1)
+ {
+ return (int)GetLastError();
+ }
+ return 0;
+}
+
#endif
Index: rutil/WinCompat.cxx
===================================================================
--- rutil/WinCompat.cxx (.../branches/resiprocate-1.8) (revision 9855)
+++ rutil/WinCompat.cxx (.../main) (revision 9855)
@@ -131,13 +131,13 @@
WinCompat* WinCompat::mInstance = 0;
+static Mutex WinComaptInstanceMutex;
WinCompat *
WinCompat::instance()
{
- static Mutex mutex;
if (!mInstance)
{
- Lock lock(mutex);
+ Lock lock(WinComaptInstanceMutex);
if (!mInstance)
{
mInstance = new WinCompat();
@@ -173,11 +173,13 @@
getBestInterfaceEx = (GetBestInterfaceExProc) GetProcAddress(hLib, TEXT("GetBestInterfaceEx"));
getAdaptersAddresses = (GetAdaptersAddressesProc) GetProcAddress(hLib, TEXT("GetAdaptersAddresses"));
getAdaptersInfo = (GetAdaptersInfoProc) GetProcAddress(hLib, TEXT("GetAdaptersInfo"));
+ getBestRoute = (GetBestRouteProc) GetProcAddress(hLib, TEXT("GetBestRoute"));
+ getIpAddrTable = (GetIpAddrTableProc) GetProcAddress(hLib, TEXT("GetIpAddrTable"));
if (getAdaptersAddresses == NULL || getBestInterfaceEx == NULL)
{
loadLibraryWithIPv6Failed = true;
}
- if (getAdaptersInfo == NULL)
+ if (getAdaptersInfo == NULL || getBestRoute == NULL || getIpAddrTable == NULL)
{
loadLibraryWithIPv4Failed = true;
}
@@ -185,6 +187,7 @@
loadLibraryWithIPv6Failed = true;
loadLibraryWithIPv4Failed = true;
#endif
+ DebugLog(<< "WinCompat constructor complete!");
}
void WinCompat::destroyInstance()
@@ -339,25 +342,31 @@
memset(&sourceIP, 0, sizeof(sockaddr_in));
sourceIP.sin_family = AF_INET;
- // look throught the local ip address - first we want to see if the address is local, if
+ // look through the local ip address - first we want to see if the address is local, if
// not then we want to look for the Best route
PMIB_IPADDRTABLE pIpAddrTable = NULL;
ULONG addrSize = 0;
// allocate the space
- if (ERROR_INSUFFICIENT_BUFFER == GetIpAddrTable(NULL, &addrSize, FALSE))
+ DWORD ret = instance()->getIpAddrTable(NULL, &addrSize, FALSE);
+ if(ERROR_INSUFFICIENT_BUFFER == ret)
{
pIpAddrTable = (PMIB_IPADDRTABLE) new char [addrSize];
+ if(pIpAddrTable == 0)
+ {
+ throw Exception("Can't find source address for destination - unable to new memory", __FILE__,__LINE__);
+ }
}
else
{
- throw Exception("Can't find source address for destination", __FILE__,__LINE__);
+ throw Exception("Can't find source address for destination (GetIpAddrTable to get buffer space failed), ret=" + Data(ret), __FILE__,__LINE__);
}
-
- if (NO_ERROR != GetIpAddrTable(pIpAddrTable, &addrSize, FALSE))
+
+ ret = instance()->getIpAddrTable(pIpAddrTable, &addrSize, FALSE);
+ if (NO_ERROR != ret)
{
- delete [] (char *) pIpAddrTable;
- return GenericIPAddress(sourceIP);
+ delete [] (char *) pIpAddrTable;
+ throw Exception("Can't find source address for destination (GetIpAddrTable failed), addrSize=" + Data(addrSize) + ", ret=" + Data(ret), __FILE__,__LINE__);
}
// Check if address is local or not
@@ -377,6 +386,7 @@
{
if(pIpAddrTable->table[j].dwIndex == dwNicIndex) // Default address is first address found for NIC
{
+ DebugLog(<< "Routing to a local address - returning default address for NIC");
sourceIP.sin_addr.s_addr = pIpAddrTable->table[j].dwAddr;
delete [] (char *) pIpAddrTable;
return GenericIPAddress(sourceIP);
@@ -389,13 +399,14 @@
MIB_IPFORWARDROW bestRoute;
memset(&bestRoute, 0, sizeof(bestRoute));
const sockaddr_in& sin = (const sockaddr_in&)destination.address;
- if (NO_ERROR != GetBestRoute(sin.sin_addr.s_addr, 0, &bestRoute))
+ ret = instance()->getBestRoute(sin.sin_addr.s_addr, 0, &bestRoute);
+ if (NO_ERROR != ret)
{
delete [] (char *) pIpAddrTable;
- throw Exception("Can't find source address for destination", __FILE__,__LINE__);
+ throw Exception("Can't find source address for destination, ret=" + Data(ret), __FILE__,__LINE__);
}
- // look throught the local ip address to find one that match the best route.
+ // look through the local ip address to find one that match the best route.
enum ENICEntryPreference {ENICUnknown = 0, ENextHopNotWithinNICSubnet, ENICSubnetIsAll1s, ENICServicesNextHop};
ENICEntryPreference eCurrSelection = ENICUnknown;
Index: rutil/FileSystem.hxx
===================================================================
--- rutil/FileSystem.hxx (.../branches/resiprocate-1.8) (revision 9855)
+++ rutil/FileSystem.hxx (.../main) (revision 9855)
@@ -5,11 +5,13 @@
#if !defined(WIN32)
#include <sys/types.h>
+#include <sys/stat.h>
#include <sys/uio.h>
#include <sys/fcntl.h>
#include <unistd.h>
#include <dirent.h>
#else
+#include <direct.h>
#include "rutil/Socket.hxx"
#endif
@@ -62,6 +64,7 @@
iterator begin() const;
iterator end() const;
const Data& getPath() const { return mPath; }
+ int create() const;
private:
Data mPath;
};
Index: rutil/Makefile.am
===================================================================
--- rutil/Makefile.am (.../branches/resiprocate-1.8) (revision 9855)
+++ rutil/Makefile.am (.../main) (revision 9855)
@@ -182,7 +182,14 @@
StlPoolAllocator.hxx \
ProducerFifoBuffer.hxx \
DinkyPool.hxx \
- ConsumerFifoBuffer.hxx
+ ConsumerFifoBuffer.hxx \
+ cajun/json/elements.h \
+ cajun/json/elements.inl \
+ cajun/json/reader.h \
+ cajun/json/reader.inl \
+ cajun/json/visitor.h \
+ cajun/json/writer.h \
+ cajun/json/writer.inl
##############################################################################
Index: configure.ac
===================================================================
--- configure.ac (.../branches/resiprocate-1.8) (revision 9855)
+++ configure.ac (.../main) (revision 9855)
@@ -1,5 +1,5 @@
-AC_INIT(resiprocate,1.8.5)
+AC_INIT(resiprocate,1.9.0)
AC_CONFIG_SRCDIR(repro/repro.cxx)
SO_RELEASE=`echo $PACKAGE_VERSION | cut -f1,2 -d.`
@@ -258,6 +258,7 @@
resip/dum/test/Makefile \
resip/certs/Makefile \
repro/Makefile \
+ repro/accountingconsumers/Makefile \
repro/reprocmd/Makefile \
repro/test/Makefile \
b2bua/Makefile \
Property changes on: .
___________________________________________________________________
Modified: svn:mergeinfo
Reverse-merged /main:r9711,9718-9732,9735-9741,9745,9748-9762,9792,9802,9805-9813,9817-9819,9823-9824,9826-9831,9838,9844-9850