Compare commits

...

200 Commits

Author SHA1 Message Date
Torsten Grote 115675d7b6 [android] Hide role-dependant private group menu items by default
and only enable them once we know our role
2018-12-18 10:30:39 -02:00
akwizgran 0089c1ac6d Merge branch '1468-restrict-image-size' into 'master'
Fix first issues related to image size

See merge request briar/briar!1018
2018-12-17 12:48:15 +00:00
akwizgran a37b6d81ed Merge branch '1242-save-snackbar-fix' into 'master'
[android] Clarify the meaning of image save state

See merge request briar/briar!1017
2018-12-17 11:17:12 +00:00
Torsten Grote 1d09a6708a [android] don't ever load an entire image into memory
This happens on API 27+28 if loading TIFF or WebP files.
Using an InputStream with a read limit prevents this.
2018-12-14 20:11:43 -02:00
Torsten Grote d3b6f484c8 [android] allow image transformations in full-screen view
to prevent crashes from huge images
2018-12-14 20:11:43 -02:00
Torsten Grote 039c6edb66 [android] increase scale levels of PhotoView 2018-12-14 20:11:43 -02:00
Torsten Grote 8b9f89eab2 [android] Clarify the meaning of image save state 2018-12-14 12:27:47 -02:00
akwizgran 1e2c17b170 Merge branch '1242-display-image-attachments-multiple' into 'master'
Swipe left/right in image screen for images from same message

See merge request briar/briar!1012
2018-12-13 16:33:24 +00:00
Torsten Grote a994966095 [android] address review comments for image fullscreen swiping 2018-12-13 12:00:51 -02:00
Torsten Grote 2bea581654 [android] Swipe left/right in image screen to see other images from the same message 2018-12-13 11:59:41 -02:00
Torsten Grote 87377666aa Merge branch '1473-display-multiple-images' into 'master'
UX for displaying multiple image attachments

Closes #1473

See merge request briar/briar!1010
2018-12-13 13:07:24 +00:00
akwizgran 9d07b2e141 Resolve merge conflicts.
# Conflicts:
#   briar-android/src/main/java/org/briarproject/briar/android/conversation/AttachmentController.java
#   briar-android/src/main/java/org/briarproject/briar/android/util/UiUtils.java
2018-12-13 11:41:04 +00:00
akwizgran 5c312b49e2 Merge branch '1438-send-image-attachments' into 'master'
Store attachments and actually attach them to sent messages

Closes #1438

See merge request briar/briar!1006
2018-12-13 10:27:09 +00:00
Torsten Grote f56efe45cd Merge branch '1477-get-client-minor-version' into 'master'
Add method for querying client minor version supported by contact

See merge request briar/briar!1014
2018-12-12 19:34:55 +00:00
Torsten Grote 2332a58681 [android] address review comments for displaying multiple images 2018-12-12 17:00:44 -02:00
Torsten Grote 8c6dfaa196 [android] Use @UiThread instead of @MainThread 2018-12-12 16:18:43 -02:00
Torsten Grote 3cfb04b60d Establish some rules for handling InputStreams
* Methods shouldn't place any special requirements on the streams
  passed into them
* This implies that if a stream's going to be marked and reset,
  that should all happen within one method
* This also implies that if a method needs to mark and reset a stream,
  it should wrap the stream in a BufferedInputStream before doing so,
  rather than requiring a markable stream to be passed in
2018-12-12 16:17:50 -02:00
Torsten Grote e85fbfb952 [android] close InputStream with new IoUtils method 2018-12-12 16:17:50 -02:00
Torsten Grote 80ee35d926 [core] Return fake mini PNG as Attachment instead of throwing exception 2018-12-12 16:17:50 -02:00
Torsten Grote 4796902b9c [android] store attachments and actually attach them to sent messages 2018-12-12 16:17:50 -02:00
akwizgran 149e67c0f7 Reduce code duplication in tests. 2018-12-12 11:57:35 +00:00
akwizgran 1d5214117f Add tests for getClientMinorVersion(). 2018-12-11 17:55:39 +00:00
akwizgran b8f248ca9c Add tests for getClientVisibility(). 2018-12-11 17:51:42 +00:00
Torsten Grote dfb71a03a5 [android] Only retrieve image sizes for single images in messages
We need to do this to know the height of messages when binding the view.
The size of single images can be different (e.g. due to orientation).
For multiple images, we use a fixed size, so no retrieval is required.
2018-12-11 15:38:05 -02:00
Torsten Grote 961fdc8e72 [android] Show multiple images in message bubble 2018-12-11 15:28:21 -02:00
Torsten Grote c3d44663cd [android] Use a nested RecyclerView with a single items to show image attachments
This is preparation for showing multiple image attachments in one
message bubble.
2018-12-11 15:28:21 -02:00
akwizgran 0081472489 Add method for querying contact's client minor version. 2018-12-11 17:25:29 +00:00
akwizgran cdf4f3a24b Merge branch '1232-add-contacts-remotely-api' into 'master'
[api] Add interface for adding contacts remotely

See merge request briar/briar!1007
2018-12-10 10:53:37 +00:00
Torsten Grote fb1d8e860f [api] Add interface for adding contacts remotely 2018-12-10 08:30:50 -02:00
akwizgran a3c526ec9a Merge branch '1298-scrub-wifi-address-in-crash-report' into 'master'
Scrub wifi IP address in crash reports.

Closes #1298

See merge request briar/briar!1013
2018-12-10 10:12:42 +00:00
Jordi Salvat dee488d06d Scrub wifi IP address in crash reports. 2018-12-10 01:07:37 +01:00
Torsten Grote b29c7d8022 Merge branch '1385-make-link-cover-entire-word' into 'master'
[android] fix start of link in error message for adding contacts

Closes #1385

See merge request briar/briar!1011
2018-12-07 19:13:54 +00:00
akwizgran 0725d207ec Merge branch '1432-headless-integration-tests' into 'master'
[headless] Add first integration test for ContactController

See merge request briar/briar!1008
2018-12-07 17:37:22 +00:00
akwizgran 5a7599a88d Merge branch '1242-display-image-attachments-save' into 'master'
Allow the user to save image attachment outside of Briar

See merge request briar/briar!1005
2018-12-07 17:31:42 +00:00
Torsten Grote 59cd98db81 [android] Get image extension from MimeTypeMap and store it in AttachmentItem 2018-12-07 15:11:09 -02:00
Torsten Grote 768488eb04 [android] Show (tinted) security icon when warning about saving attachments 2018-12-07 14:39:43 -02:00
Torsten Grote a6b1ad48c3 [android] Add support for saving image attachments on API < 19
This is done by using the WRITE_EXTERNAL_STORAGE permission
to write the file directly without using the system activity.
2018-12-07 13:01:44 -02:00
Torsten Grote 77299a68ed [android] Allow the user to save image attachment outside of Briar 2018-12-07 13:01:42 -02:00
akwizgran 5e5705c73b Merge branch '1438-send-image-attachments-ui' into 'master'
Implement UX for sending image attachments

See merge request briar/briar!1004
2018-12-07 14:58:23 +00:00
Torsten Grote e6229a3a13 [android] Factor out image preview into its own view class 2018-12-06 17:56:02 -02:00
Torsten Grote 5fbacb4ee4 [android] Split out an EmojiTextInputView from TextInputViews
This also removes the TextInputController whose job is now done by the view.
2018-12-06 17:56:02 -02:00
Torsten Grote c7f4e976ed [android] Require users of TextInputView to set its controller 2018-12-06 17:56:02 -02:00
Torsten Grote 419f2d966a [android] Show a toast when an image could not be attached 2018-12-06 17:56:02 -02:00
Torsten Grote d6c18db9e9 [android] set image preview size to 1/4 of screen height 2018-12-06 17:56:02 -02:00
Torsten Grote 8fe49d9961 [android] Re-factor TextInputViews 2018-12-06 17:56:02 -02:00
Torsten Grote f536cfdab8 [android] first round of review comments for attaching images 2018-12-06 17:56:02 -02:00
Torsten Grote 4d594acad5 [android] Save attached (but not sent) image on screen rotation 2018-12-06 17:56:02 -02:00
Torsten Grote 800dfed5c1 [android] support adding image attachments to private messages 2018-12-06 17:55:59 -02:00
Jordi Salvat 54b823e401 [android] fix start of link in error message for adding contacts 2018-12-06 20:44:36 +01:00
Torsten Grote 52ec56d690 Merge branch 'invalid-slide-direction' into 'master'
Revert change to slide direction

Closes #1478

See merge request briar/briar!1009
2018-12-06 15:32:07 +00:00
akwizgran 7b3afcca99 Revert change to slide direction. 2018-12-06 15:18:16 +00:00
Torsten Grote a22d03d028 [headless] wait for lifecycle manager to finish starting
before starting web server
2018-12-05 16:08:03 -02:00
Torsten Grote d857338ad0 [headless] Add first integration test for ContactController 2018-12-05 16:04:14 -02:00
akwizgran a5c9e7c74d Merge branch '1242-display-image-attachments-fullscreen' into 'master'
Add ImageActivity to show image attachment in full-screen

See merge request briar/briar!999
2018-11-30 18:04:55 +00:00
Torsten Grote 8a4a343147 [android] Move image to the top if it is overlapping the toolbar 2018-11-30 15:53:38 -02:00
Torsten Grote 7b22d3b84d [android] Address review issues for image fullscreen view 2018-11-28 17:26:01 -02:00
Torsten Grote c8fa23273f [android] support pull down to dismiss pattern for ImageActivity 2018-11-28 17:26:01 -02:00
Torsten Grote fbe5df8938 [android] Add ImageActivity to show images in full-screen 2018-11-28 17:26:01 -02:00
akwizgran 008cf95741 Merge branch '1467-conversation-scrolling' into 'master'
Only scroll conversation list to bottom, when already at bottom

Closes #1467

See merge request briar/briar!1000
2018-11-27 09:32:05 +00:00
Torsten Grote 3eb066a836 [android] Use new IoUtils to close InputStreams 2018-11-26 16:28:06 -02:00
Torsten Grote 674b29af25 [android] static constant all caps 2018-11-26 16:23:51 -02:00
Torsten Grote b8ca5ab557 [android] Only scroll conversation list to bottom, when already at bottom
Closes #1467
2018-11-26 16:23:17 -02:00
Torsten Grote 6e17709f46 Merge branch 'try-to-close' into 'master'
Move tryToClose() methods into utility classes

See merge request briar/briar!1002
2018-11-26 18:22:24 +00:00
akwizgran 726d90145c Merge branch '1242-display-image-attachments' into 'master'
[android] display image attachments for conversation messages

See merge request briar/briar!997
2018-11-26 17:19:37 +00:00
Torsten Grote 165211eb9b Merge branch '1259-headless-mac-os' into 'master'
Enable headless app to start on MacOS

See merge request briar/briar!1003
2018-11-26 12:01:27 +00:00
akwizgran 868c61e5d6 Move tryToClose() methods into utility classes. 2018-11-23 15:02:27 +00:00
Torsten Grote 798bb6d4f7 [android] scale thumbnails to minimum size, don't upscale to maximum size 2018-11-23 11:25:18 -02:00
akwizgran bc352a2dc6 Enable Tor on Mac OS once binaries are available. 2018-11-23 13:07:12 +00:00
akwizgran ce7d6d3db5 Code cleanup. 2018-11-23 12:56:34 +00:00
akwizgran 61276c81d2 Make it possible to start the headless app on MacOS.
The app is still non-functional because we don't have a Tor plugin.
2018-11-23 12:52:40 +00:00
Torsten Grote c09abdb088 Merge branch 'location-permission-sdk-23' into 'master'
Change location permission to uses-permission-sdk-23

See merge request briar/briar!1001
2018-11-22 12:03:07 +00:00
akwizgran 45a11badd5 Change location permission to uses-permission-sdk-23. 2018-11-20 16:16:47 +00:00
Torsten Grote 152ac3df43 [android] improve bitmap transformation hashKey and DiskCacheKey 2018-11-20 11:49:21 -02:00
Torsten Grote dd5ad86db8 [android] Use DataFetcherFactory to create data fetchers and allow cancelling loads 2018-11-20 11:49:21 -02:00
Torsten Grote 10e9fb308d [android] Display Image Attachements: Address first round of review comments 2018-11-19 20:35:07 -02:00
Torsten Grote de8e95692a [android] support RTL languages when rounding thumbnail corners 2018-11-19 20:35:07 -02:00
Torsten Grote d6b52cf4ec [android] Use our own BitmapTransformation for rounded image corners 2018-11-19 20:35:07 -02:00
Torsten Grote 8a839fb5e4 [android] display image attachments for conversation messages 2018-11-19 20:35:07 -02:00
akwizgran fbf8642edb Merge branch '1464-message-status-mixed' into 'master'
[core] fix wrong order of message status flags in conversation headers

Closes #1464

See merge request briar/briar!998
2018-11-16 13:44:39 +00:00
Torsten Grote ade6a14342 Merge branch 'validation-refactoring' into 'master'
Reorganise validation code

See merge request briar/briar!991
2018-11-15 17:18:15 +00:00
Torsten Grote d500ff81c3 Merge branch 'require-non-null' into 'master'
Add static requireNonNull() method

See merge request briar/briar!996
2018-11-15 16:50:16 +00:00
Torsten Grote 3053e3cfa7 [core] fix wrong order of message status flags in conversation headers 2018-11-15 14:39:05 -02:00
akwizgran 6964a67ca3 Add static requireNonNull() method. 2018-11-15 11:13:15 +00:00
Torsten Grote f4b06e1fb3 Merge branch 'load-latest-message-eagerly' into 'master'
Load latest message eagerly

See merge request briar/briar!995
2018-11-14 16:01:59 +00:00
akwizgran 4db075d643 Only consider the latest item for preloading. 2018-11-14 15:13:25 +00:00
akwizgran 78a8ae6b8e Sort headers and eagerly load text of latest message. 2018-11-14 15:01:54 +00:00
Torsten Grote 7866037d02 Merge branch '1460-introduction-request-text' into 'master'
Show correct text when an existing contact is introduced

Closes #1460

See merge request briar/briar!994
2018-11-14 11:23:26 +00:00
akwizgran 35716051fb Show correct text when an existing contact is introduced. 2018-11-14 11:05:46 +00:00
Torsten Grote 6cafea836f Merge branch 'eager-singletons' into 'master'
Singletons that call registration methods must be eager

See merge request briar/briar!993
2018-11-13 18:03:28 +00:00
akwizgran bd0fd229c6 Merge branch '1242-attachment-input-stream' into 'master'
Attachments will use InputStream rather than ByteBuffer

See merge request briar/briar!992
2018-11-13 17:41:39 +00:00
akwizgran ea05a5c703 Singletons that call registration methods must be eager. 2018-11-13 17:40:06 +00:00
akwizgran 4103eaf639 Reorganise validation code (no functional changes). 2018-11-13 17:16:47 +00:00
Torsten Grote 753a25bc2a [core] Attachments will use InputStream rather than ByteBuffer 2018-11-13 15:12:34 -02:00
akwizgran 8f4c3c4528 Bump version numbers for 1.1.5 release. 2018-11-13 13:01:01 +00:00
akwizgran 636a7dfe72 Update translations. 2018-11-13 12:59:51 +00:00
akwizgran 08e99edd42 Merge branch 'unpack-tor-binaries' into 'master'
Always unpack and include latest Tor binaries

See merge request briar/briar!987
2018-11-13 12:56:47 +00:00
akwizgran e28bc475df Merge branch '1242-optional-message-text' into 'master'
Add support for private messages without text

See merge request briar/briar!990
2018-11-13 10:47:52 +00:00
Torsten Grote 88276a4d44 Add support for private messages without text 2018-11-12 18:11:03 -02:00
akwizgran f9987c89df Merge branch 'disable-tor-connection-padding' into 'master'
Disable Tor's connection padding

See merge request briar/briar!989
2018-11-12 14:03:22 +00:00
Torsten Grote 2c8cb8301f Merge branch '1455-stream-context-may-be-null' into 'master'
Stream context may be null

Closes #1455

See merge request briar/briar!988
2018-11-12 12:50:01 +00:00
akwizgran c00ee80f0f Update test expectations. 2018-11-12 12:20:04 +00:00
akwizgran 3bfedfdc3d Add action for nullable DB callables. 2018-11-12 12:16:42 +00:00
akwizgran ecb63d1acb Add interface for DB tasks will nullable results. 2018-11-12 12:13:26 +00:00
akwizgran b24914408d Stream context may be null. 2018-11-12 11:31:59 +00:00
akwizgran 5ede63edd5 Always unpack and include latest Tor binaries. 2018-11-08 17:48:26 +00:00
akwizgran 4e523c5fbc Merge branch '1242-display-image-attachments' into 'master'
[android] refactor conversation items and view holders

See merge request briar/briar!984
2018-11-08 16:08:58 +00:00
akwizgran cf79ed5633 IntentFilter may not be thread-safe. 2018-11-08 14:54:53 +00:00
akwizgran 0a0a6a6369 Disable Tor's connection padding on mobile data or battery. 2018-11-08 14:50:36 +00:00
akwizgran 4784980e7b No need to broadcast network status at startup. 2018-11-08 14:50:36 +00:00
akwizgran 3bfa5e2081 [android] Move ConversationListener to top level. 2018-11-08 10:27:36 -02:00
akwizgran f2b09deac4 [android] Remove type parameter from view holders. 2018-11-08 10:27:29 -02:00
Torsten Grote ad4729b2f9 [android] refactor conversation items and view holders
This is a preparation for image support.
2018-11-08 10:27:29 -02:00
akwizgran 50cc0a6815 Merge branch '1452-websocket-authentication' into 'master'
[headless] change websocket authentication from basic auth to token message

Closes #1452

See merge request briar/briar!986
2018-11-08 12:26:53 +00:00
Torsten Grote 32c8ac6576 [headless] change websocket authentication from basic auth to token message 2018-11-08 10:15:17 -02:00
akwizgran c12422d949 Merge branch '1434-android-conversation-package' into 'master'
Move conversation classes into their own package

See merge request briar/briar!978
2018-11-08 11:01:36 +00:00
akwizgran 3841713c18 Merge branch 'upgrade_roboletric_to_401' into 'master'
Upgrade robolectric to 4.0.1

See merge request briar/briar!980
2018-11-08 11:00:08 +00:00
akwizgran 79232eb558 Merge branch 'headless-fixes' into 'master'
Headless fixes

See merge request briar/briar!985
2018-11-08 10:55:28 +00:00
Torsten Grote d02b30e751 Merge branch 'use-transactional-db-api' into 'master'
Use transactional database API in Bramble

See merge request briar/briar!974
2018-11-07 19:06:26 +00:00
akwizgran 043662a092 Code cleanup. 2018-11-07 18:31:07 +00:00
Torsten Grote efc85fb88f [headless] don't use putAll for a single field 2018-11-07 15:24:20 -03:00
Torsten Grote 8b3983ef9e [headless] only offload to DatabaseExecutor when needed
when receiving a new conversation message
2018-11-07 15:24:20 -03:00
Torsten Grote 6766fb76b2 [headless] upgrade javalin and mockk 2018-11-07 15:18:46 -03:00
Torsten Grote 7f74bd1c38 [headless] Use --user for websocket example request
The authentication token can contain slashes.
When used as part of the URL, the URL becomes invalid.
Therefore, using curl's user parameter is preferrable.
2018-11-07 15:18:46 -03:00
akwizgran 951ee30b95 Update tests. 2018-11-07 18:18:30 +00:00
akwizgran c386a0f5eb Replace Maybe with nullable transaction method. 2018-11-07 18:18:30 +00:00
akwizgran 52c778dce3 Reformat code. 2018-11-07 18:18:27 +00:00
akwizgran e846a13f50 Use transactional database API in Bramble. 2018-11-07 18:14:10 +00:00
akwizgran 23e9b119d1 Merge branch '1434-message-attachments' into 'master'
Add attachment API for sending/retreiving private messages

See merge request briar/briar!976
2018-11-07 18:08:36 +00:00
akwizgran e6f380296f Merge branch '1451-briar-headless-test-other-modules' into 'master'
[headless] Limit tests in Android Studio to headless package

Closes #1451

See merge request briar/briar!983
2018-11-07 17:47:37 +00:00
Torsten Grote 794fb9686b [headless] Limit tests in Android Studio to headless package 2018-11-07 13:46:49 -03:00
Torsten Grote bb22b9db10 Merge branch 'remove-hamcrest-dependencies' into 'master'
Remove redundant dependency declarations

See merge request briar/briar!981
2018-11-07 16:37:30 +00:00
Julian Dehm d4f015d054 Upgrade robolectric to 4.0.1 2018-11-07 17:11:21 +01:00
akwizgran 41e5d8900c Remove redundant dependency declarations. 2018-11-07 16:10:39 +00:00
Torsten Grote c3cb966009 [android] move conversation classes into their own package 2018-11-07 11:48:20 -03:00
Torsten Grote f964d1ef07 Fix receivers of ConversationMessageReceivedEvent
These were only listening to private message events, ignoring all others
2018-11-07 11:34:11 -03:00
Torsten Grote cccaeeda6c [core] Add API to add messages with attachments 2018-11-07 11:34:11 -03:00
Torsten Grote 483106e00c [core] Add MessagingManager#getAttachment() 2018-11-07 11:34:11 -03:00
Torsten Grote 934f14ef31 [core] Add attachment support to private messages 2018-11-07 11:34:09 -03:00
Torsten Grote e3abff5ad8 Refactor PrivateMessageHeader to ConversationMessageHeader base-class
This is preparation for adding attachments to private messages
2018-11-07 11:33:37 -03:00
Torsten Grote 391732b239 Merge branch 'change-contact-name' into 'master'
Change button text to match name of action

See merge request briar/briar!979
2018-11-07 12:11:22 +00:00
akwizgran 4738bfdd85 Ignore missing translations. 2018-11-07 10:43:13 +00:00
akwizgran be1ca89309 Change button text to match name of action. 2018-11-07 10:40:59 +00:00
Torsten Grote 866be99179 Merge branch '41-alias-frontend' into 'master'
Add UI for changing contact aliases

Closes #41

See merge request briar/briar!965
2018-11-06 18:09:47 +00:00
akwizgran 48822e2133 Merge branch '1381-introduction-test-fails' into 'master'
Fix non-determinism of Introduction integration tests

Closes #1381

See merge request briar/briar!970
2018-11-06 18:00:48 +00:00
Torsten Grote 6883c5caa9 [android] address last contact aliases review issues 2018-11-06 14:57:39 -03:00
Torsten Grote 8b709969ab [android] pass ContactId via ViewModel to AliasDialogFragment 2018-11-06 13:42:51 -03:00
Torsten Grote fe94b65b3b [android] Fix double loading of conversation messages when rotating screen 2018-11-06 13:42:51 -03:00
akwizgran f54df1d787 Reduce visibility, remove unnecessary rethrow. 2018-11-06 13:42:51 -03:00
akwizgran a7e826ccf5 Remove qualification from java.lang.Runnable. 2018-11-06 13:42:51 -03:00
akwizgran 845eb3262b Use expression lambda. 2018-11-06 13:42:51 -03:00
akwizgran 0a46ad439f Check whether activity is null. 2018-11-06 13:42:51 -03:00
akwizgran d14d93ea35 Require observed data to be non-null. 2018-11-06 13:42:51 -03:00
akwizgran 12a1cf8f8b Reuse Observer interface. 2018-11-06 13:42:51 -03:00
akwizgran fb2ab861db Fix some lint warnings. 2018-11-06 13:42:51 -03:00
Torsten Grote aa15b68d24 [android] Reload conversation when contact name changes 2018-11-06 13:42:51 -03:00
Torsten Grote 7059f376f1 [android] Add UI for changing contact alias
This introduces the first ViewModel to share state between the
ConversationActivity and the AliasDialogFragment.
2018-11-06 13:42:51 -03:00
akwizgran 9313c191c1 Merge branch 'ui-fixes' into 'master'
Small UI fixes

See merge request briar/briar!975
2018-11-05 10:40:09 +00:00
akwizgran 7746364ae9 Merge branch '1437-reversed-emoji' into 'master'
[android] Add new emojis to the beginning of the list of recently used ones

Closes #1437

See merge request briar/briar!977
2018-11-05 10:27:03 +00:00
Torsten Grote 7429857b28 [android] Add new emojis to the beginning of the list of recently used ones
Otherwise the list will be reversed with most recently used at the end.
2018-11-04 11:08:05 -03:00
Torsten Grote 4db64f51a8 [android] Use same color for all messages in private groups 2018-11-02 15:59:49 -03:00
Torsten Grote 78172038ef [android] Always center selectable contacts vertically 2018-11-02 15:38:01 -03:00
Torsten Grote 7d0c418877 [android] Align short incoming messages on the left 2018-11-02 15:37:16 -03:00
Torsten Grote 5ae4f8f6cb [core] Fix non-determism in GroupInvitationIntegrationTest 2018-11-02 14:08:42 -03:00
Torsten Grote 45dd10db9d [core] Fix non-determinism in introduction integration tests 2018-11-02 14:08:42 -03:00
Torsten Grote 5cc8c268ca [core] Re-add message counter and put debug output behind flag 2018-11-02 14:08:42 -03:00
akwizgran 93a6bf2f52 Add logging to debug test failures. 2018-11-02 12:48:23 -03:00
akwizgran 852dd46a1b Utility class for converting BDF to strings.
(cherry picked from commit 9e94917)
2018-11-02 12:48:23 -03:00
Torsten Grote 4a42e767d3 [core] Add a detector for message delivery non-determinism 2018-11-02 12:48:13 -03:00
akwizgran 8547b4dc91 Merge branch 'upgrade-dagger' into 'master'
Upgrade dagger

See merge request briar/briar!973
2018-11-01 14:17:35 +00:00
akwizgran f6c8a8cec7 Move dagger.gradle to project root. 2018-11-01 14:05:46 +00:00
Torsten Grote db8796049e gradle: Factor out dagger apt code into its own file 2018-11-01 10:45:59 -03:00
Torsten Grote e1f31ad381 Remove gradle-apt-plugin since it isn't stricly needed anymore
Reference: https://github.com/tbroyer/gradle-apt-plugin/blob/6b2ee87fbf52ee09f70fb585d37e1d834da5ae3e/README.md
2018-10-31 16:01:57 -03:00
Torsten Grote 3a15e47ddd Upgrade Dagger to latest version 2018-10-31 15:57:21 -03:00
Torsten Grote cf616905d6 Merge branch 'introduction-manager-skip-session-parsing' into 'master'
Avoid some unnecessary session parsing when retrieving introduction messages

See merge request briar/briar!972
2018-10-31 16:36:59 +00:00
akwizgran d3f774f339 Avoid some unnecessary session parsing. 2018-10-31 16:18:33 +00:00
akwizgran 6c7c488892 Merge branch '41-alias-frontend-base' into 'master'
[android] Show contact aliases in UI

See merge request briar/briar!971
2018-10-31 16:16:38 +00:00
Torsten Grote 3fe7aae97e Contact aliases: address review comments 2018-10-31 13:06:19 -03:00
Torsten Grote ecf417c93b [android] Show contact alias in remaining places 2018-10-31 13:06:19 -03:00
Torsten Grote c1785c5b13 [android] Show contact alias in contact lists 2018-10-31 13:06:19 -03:00
Torsten Grote fb2c321a3d [android] Show contact alias inside private groups and their memberlist 2018-10-31 13:06:19 -03:00
Torsten Grote 6e3adc0874 Show alias for introduction notices in private conversation 2018-10-31 13:06:19 -03:00
Torsten Grote cdbe2a00f5 [android] Show alias for creator of private group in list of private groups 2018-10-31 11:40:17 -03:00
Torsten Grote a51dc7e0d5 [android] Show Author alias in AuthorView 2018-10-31 11:40:15 -03:00
Torsten Grote 0ee7465429 Merge branch '41-alias-author-info' into 'master'
Refactor Author.Status into dedicated AuthorInfo class and add alias

See merge request briar/briar!968
2018-10-30 19:33:39 +00:00
Torsten Grote 7c202189a2 [bramble] Implement equals() and hashCode() for AuthorView 2018-10-30 15:21:09 -03:00
akwizgran da3b2c1591 Merge branch '41-alias-backend' into 'master'
Add backend support for contact aliases

See merge request briar/briar!963
2018-10-30 16:43:52 +00:00
Torsten Grote 6c5e8ce4cf Rename remaining occurrences of status to authorInfo 2018-10-30 13:40:04 -03:00
Torsten Grote ca700d8d23 [bramble] address review comments 2018-10-30 13:32:56 -03:00
akwizgran db11dad61e Merge branch 'clean-tor-binaries' into 'master'
Delete Tor binaries when cleaning

See merge request briar/briar!969
2018-10-30 13:59:21 +00:00
akwizgran 69e7366226 Merge branch '1433-illegal-characters' into 'master'
Handle illegal byte sequences safely in BdfReaderImpl

Closes #1433

See merge request briar/briar!967
2018-10-30 13:58:36 +00:00
akwizgran 90b7b4e67f Merge branch '1416-obfs4' into 'master'
Add obfs4proxy and switch to obfs4 bridges

Closes #1417

See merge request briar/briar!964
2018-10-30 13:58:13 +00:00
akwizgran d29812a42b Delete Tor binaries when cleaning. 2018-10-30 13:06:06 +00:00
akwizgran 6565172e10 Bump version numbers for 1.1.4 release. 2018-10-29 17:31:09 +00:00
akwizgran 7447468ce5 Update translations. 2018-10-29 17:30:04 +00:00
akwizgran 2db2a1a208 Replace a slow bridge with a faster one. 2018-10-29 17:25:12 +00:00
akwizgran 0d7e4feaf2 Throw AssertionError to make intent clearer. 2018-10-29 17:02:07 +00:00
akwizgran eb3983f6b2 Use safe ASCII decoding in ModemImpl. 2018-10-29 16:48:18 +00:00
akwizgran e2ce49c30e Use safe UTF-8 decoding in BdfReaderImpl. 2018-10-29 16:47:55 +00:00
akwizgran adc6fb2fd5 Add fuzzing test for illegal UTF-8 byte sequences. 2018-10-29 16:44:02 +00:00
Torsten Grote ca6dc33cdd Add obfs4 proxy and switch to obfs4 bridges 2018-10-25 09:38:44 -03:00
393 changed files with 8994 additions and 4615 deletions
+1 -1
View File
@@ -3,7 +3,7 @@
<module name="briar-headless" />
<option name="ALTERNATIVE_JRE_PATH_ENABLED" value="false" />
<option name="ALTERNATIVE_JRE_PATH" />
<option name="PACKAGE_NAME" value="" />
<option name="PACKAGE_NAME" value="org.briarproject.briar.headless" />
<option name="MAIN_CLASS_NAME" value="" />
<option name="METHOD_NAME" value="" />
<option name="TEST_OBJECT" value="package" />
+26 -7
View File
@@ -1,3 +1,5 @@
import com.android.build.gradle.tasks.MergeResources
apply plugin: 'com.android.library'
apply plugin: 'witness'
apply from: 'witness.gradle'
@@ -9,8 +11,8 @@ android {
defaultConfig {
minSdkVersion 14
targetSdkVersion 26
versionCode 10103
versionName "1.1.3"
versionCode 10105
versionName "1.1.5"
consumerProguardFiles 'proguard-rules.txt'
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
@@ -29,8 +31,9 @@ configurations {
dependencies {
implementation project(path: ':bramble-core', configuration: 'default')
tor 'org.briarproject:tor-android:0.3.4.8@zip'
tor 'org.briarproject:obfs4proxy-android:0.0.7@zip'
annotationProcessor 'com.google.dagger:dagger-compiler:2.0.2'
annotationProcessor 'com.google.dagger:dagger-compiler:2.19'
compileOnly 'javax.annotation:jsr250-api:1.0'
@@ -39,13 +42,29 @@ dependencies {
testImplementation "org.jmock:jmock:2.8.2"
testImplementation "org.jmock:jmock-junit4:2.8.2"
testImplementation "org.jmock:jmock-legacy:2.8.2"
testImplementation "org.hamcrest:hamcrest-library:1.3"
testImplementation "org.hamcrest:hamcrest-core:1.3"
}
project.afterEvaluate {
def torBinariesDir = 'src/main/res/raw'
task cleanTorBinaries {
doLast {
delete fileTree(torBinariesDir) { include '*.zip' }
}
}
clean.dependsOn cleanTorBinaries
task unpackTorBinaries {
doLast {
copy {
from configurations.tor.collect { zipTree(it) }
into 'src/main/res/raw'
into torBinariesDir
}
}
dependsOn cleanTorBinaries
}
tasks.withType(MergeResources) {
inputs.dir torBinariesDir
dependsOn unpackTorBinaries
}
@@ -0,0 +1,11 @@
package org.briarproject.bramble;
import org.briarproject.bramble.battery.AndroidBatteryModule;
import org.briarproject.bramble.network.AndroidNetworkModule;
public interface BrambleAndroidEagerSingletons {
void inject(AndroidBatteryModule.EagerSingletons init);
void inject(AndroidNetworkModule.EagerSingletons init);
}
@@ -1,5 +1,6 @@
package org.briarproject.bramble;
import org.briarproject.bramble.battery.AndroidBatteryModule;
import org.briarproject.bramble.network.AndroidNetworkModule;
import org.briarproject.bramble.plugin.tor.CircumventionModule;
import org.briarproject.bramble.system.AndroidSystemModule;
@@ -7,10 +8,15 @@ import org.briarproject.bramble.system.AndroidSystemModule;
import dagger.Module;
@Module(includes = {
AndroidBatteryModule.class,
AndroidNetworkModule.class,
AndroidSystemModule.class,
CircumventionModule.class
})
public class BrambleAndroidModule {
public static void initEagerSingletons(BrambleAndroidEagerSingletons c) {
c.inject(new AndroidBatteryModule.EagerSingletons());
c.inject(new AndroidNetworkModule.EagerSingletons());
}
}
@@ -0,0 +1,84 @@
package org.briarproject.bramble.battery;
import android.app.Application;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import org.briarproject.bramble.api.battery.BatteryManager;
import org.briarproject.bramble.api.battery.event.BatteryEvent;
import org.briarproject.bramble.api.event.EventBus;
import org.briarproject.bramble.api.lifecycle.Service;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.logging.Logger;
import javax.inject.Inject;
import static android.content.Intent.ACTION_BATTERY_CHANGED;
import static android.content.Intent.ACTION_POWER_CONNECTED;
import static android.content.Intent.ACTION_POWER_DISCONNECTED;
import static android.os.BatteryManager.BATTERY_STATUS_CHARGING;
import static android.os.BatteryManager.BATTERY_STATUS_FULL;
import static android.os.BatteryManager.EXTRA_STATUS;
import static java.util.logging.Level.INFO;
import static java.util.logging.Logger.getLogger;
class AndroidBatteryManager implements BatteryManager, Service {
private static final Logger LOG =
getLogger(AndroidBatteryManager.class.getName());
private final Context appContext;
private final EventBus eventBus;
private final AtomicBoolean used = new AtomicBoolean(false);
private volatile BroadcastReceiver batteryReceiver = null;
@Inject
AndroidBatteryManager(Application app, EventBus eventBus) {
this.appContext = app.getApplicationContext();
this.eventBus = eventBus;
}
@Override
public boolean isCharging() {
// Get the sticky intent for ACTION_BATTERY_CHANGED
IntentFilter filter = new IntentFilter(ACTION_BATTERY_CHANGED);
Intent i = appContext.registerReceiver(null, filter);
if (i == null) return false;
int status = i.getIntExtra(EXTRA_STATUS, -1);
return status == BATTERY_STATUS_CHARGING ||
status == BATTERY_STATUS_FULL;
}
@Override
public void startService() {
if (used.getAndSet(true)) throw new IllegalStateException();
batteryReceiver = new BatteryReceiver();
IntentFilter filter = new IntentFilter();
filter.addAction(ACTION_POWER_CONNECTED);
filter.addAction(ACTION_POWER_DISCONNECTED);
appContext.registerReceiver(batteryReceiver, filter);
}
@Override
public void stopService() {
if (batteryReceiver != null)
appContext.unregisterReceiver(batteryReceiver);
}
private class BatteryReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context ctx, Intent i) {
String action = i.getAction();
if (LOG.isLoggable(INFO)) LOG.info("Received broadcast " + action);
if (ACTION_POWER_CONNECTED.equals(action))
eventBus.broadcast(new BatteryEvent(true));
else if (ACTION_POWER_DISCONNECTED.equals(action))
eventBus.broadcast(new BatteryEvent(false));
}
}
}
@@ -0,0 +1,27 @@
package org.briarproject.bramble.battery;
import org.briarproject.bramble.api.battery.BatteryManager;
import org.briarproject.bramble.api.lifecycle.LifecycleManager;
import javax.inject.Inject;
import javax.inject.Singleton;
import dagger.Module;
import dagger.Provides;
@Module
public class AndroidBatteryModule {
public static class EagerSingletons {
@Inject
BatteryManager batteryManager;
}
@Provides
@Singleton
BatteryManager provideBatteryManager(LifecycleManager lifecycleManager,
AndroidBatteryManager batteryManager) {
lifecycleManager.registerService(batteryManager);
return batteryManager;
}
}
@@ -3,6 +3,7 @@ package org.briarproject.bramble.network;
import org.briarproject.bramble.api.lifecycle.LifecycleManager;
import org.briarproject.bramble.api.network.NetworkManager;
import javax.inject.Inject;
import javax.inject.Singleton;
import dagger.Module;
@@ -11,6 +12,11 @@ import dagger.Provides;
@Module
public class AndroidNetworkModule {
public static class EagerSingletons {
@Inject
NetworkManager networkManager;
}
@Provides
@Singleton
NetworkManager provideNetworkManager(LifecycleManager lifecycleManager,
@@ -18,8 +18,8 @@ import org.briarproject.bramble.api.plugin.duplex.DuplexTransportConnection;
import org.briarproject.bramble.api.system.AndroidExecutor;
import org.briarproject.bramble.api.system.Clock;
import org.briarproject.bramble.util.AndroidUtils;
import org.briarproject.bramble.util.IoUtils;
import java.io.Closeable;
import java.io.IOException;
import java.security.SecureRandom;
import java.util.ArrayList;
@@ -51,7 +51,6 @@ import static android.bluetooth.BluetoothDevice.EXTRA_DEVICE;
import static java.util.concurrent.TimeUnit.MILLISECONDS;
import static java.util.logging.Level.INFO;
import static java.util.logging.Level.WARNING;
import static org.briarproject.bramble.util.LogUtils.logException;
import static org.briarproject.bramble.util.PrivacyUtils.scrubMacAddress;
@MethodsNotNullByDefault
@@ -161,11 +160,7 @@ class AndroidBluetoothPlugin extends BluetoothPlugin<BluetoothServerSocket> {
@Override
void tryToClose(@Nullable BluetoothServerSocket ss) {
try {
if (ss != null) ss.close();
} catch (IOException e) {
logException(LOG, WARNING, e);
}
IoUtils.tryToClose(ss, LOG, WARNING);
}
@Override
@@ -195,7 +190,7 @@ class AndroidBluetoothPlugin extends BluetoothPlugin<BluetoothServerSocket> {
s.connect();
return wrapSocket(s);
} catch (IOException e) {
tryToClose(s);
IoUtils.tryToClose(s, LOG, WARNING);
throw e;
}
}
@@ -268,14 +263,6 @@ class AndroidBluetoothPlugin extends BluetoothPlugin<BluetoothServerSocket> {
return addresses;
}
private void tryToClose(@Nullable Closeable c) {
try {
if (c != null) c.close();
} catch (IOException e) {
logException(LOG, WARNING, e);
}
}
private class BluetoothStateReceiver extends BroadcastReceiver {
@Override
@@ -6,6 +6,7 @@ import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
import android.os.PowerManager;
import org.briarproject.bramble.api.battery.BatteryManager;
import org.briarproject.bramble.api.network.NetworkManager;
import org.briarproject.bramble.api.nullsafety.MethodsNotNullByDefault;
import org.briarproject.bramble.api.nullsafety.ParametersNotNullByDefault;
@@ -41,17 +42,18 @@ class AndroidTorPlugin extends TorPlugin {
Context appContext, NetworkManager networkManager,
LocationUtils locationUtils, SocketFactory torSocketFactory,
Clock clock, ResourceProvider resourceProvider,
CircumventionProvider circumventionProvider, Backoff backoff,
CircumventionProvider circumventionProvider,
BatteryManager batteryManager, Backoff backoff,
DuplexPluginCallback callback, String architecture, int maxLatency,
int maxIdleTime) {
super(ioExecutor, networkManager, locationUtils, torSocketFactory,
clock, resourceProvider, circumventionProvider, backoff,
callback, architecture, maxLatency, maxIdleTime,
clock, resourceProvider, circumventionProvider, batteryManager,
backoff, callback, architecture, maxLatency, maxIdleTime,
appContext.getDir("tor", MODE_PRIVATE));
this.appContext = appContext;
PowerManager pm = (PowerManager)
appContext.getSystemService(POWER_SERVICE);
assert pm != null;
if (pm == null) throw new AssertionError();
wakeLock = new RenewableWakeLock(pm, scheduler, PARTIAL_WAKE_LOCK,
WAKE_LOCK_TAG, 1, MINUTES);
}
@@ -3,6 +3,7 @@ package org.briarproject.bramble.plugin.tor;
import android.content.Context;
import android.os.Build;
import org.briarproject.bramble.api.battery.BatteryManager;
import org.briarproject.bramble.api.event.EventBus;
import org.briarproject.bramble.api.network.NetworkManager;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
@@ -48,6 +49,7 @@ public class AndroidTorPluginFactory implements DuplexPluginFactory {
private final BackoffFactory backoffFactory;
private final ResourceProvider resourceProvider;
private final CircumventionProvider circumventionProvider;
private final BatteryManager batteryManager;
private final Clock clock;
public AndroidTorPluginFactory(Executor ioExecutor,
@@ -55,7 +57,8 @@ public class AndroidTorPluginFactory implements DuplexPluginFactory {
NetworkManager networkManager, LocationUtils locationUtils,
EventBus eventBus, SocketFactory torSocketFactory,
BackoffFactory backoffFactory, ResourceProvider resourceProvider,
CircumventionProvider circumventionProvider, Clock clock) {
CircumventionProvider circumventionProvider,
BatteryManager batteryManager, Clock clock) {
this.ioExecutor = ioExecutor;
this.scheduler = scheduler;
this.appContext = appContext;
@@ -66,6 +69,7 @@ public class AndroidTorPluginFactory implements DuplexPluginFactory {
this.backoffFactory = backoffFactory;
this.resourceProvider = resourceProvider;
this.circumventionProvider = circumventionProvider;
this.batteryManager = batteryManager;
this.clock = clock;
}
@@ -104,8 +108,8 @@ public class AndroidTorPluginFactory implements DuplexPluginFactory {
MAX_POLLING_INTERVAL, BACKOFF_BASE);
AndroidTorPlugin plugin = new AndroidTorPlugin(ioExecutor, scheduler,
appContext, networkManager, locationUtils, torSocketFactory,
clock, resourceProvider, circumventionProvider, backoff,
callback, architecture, MAX_LATENCY, MAX_IDLE_TIME);
clock, resourceProvider, circumventionProvider, batteryManager,
backoff, callback, architecture, MAX_LATENCY, MAX_IDLE_TIME);
eventBus.addListener(plugin);
return plugin;
}
@@ -1,5 +1,6 @@
package org.briarproject.bramble.system;
import android.annotation.SuppressLint;
import android.app.Application;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
@@ -26,7 +27,7 @@ import static android.provider.Settings.Secure.ANDROID_ID;
@Immutable
@NotNullByDefault
class AndroidSecureRandomProvider extends LinuxSecureRandomProvider {
class AndroidSecureRandomProvider extends UnixSecureRandomProvider {
private static final int SEED_LENGTH = 32;
@@ -37,6 +38,7 @@ class AndroidSecureRandomProvider extends LinuxSecureRandomProvider {
appContext = app.getApplicationContext();
}
@SuppressLint("HardwareIds")
@Override
protected void writeToEntropyPool(DataOutputStream out) throws IOException {
super.writeToEntropyPool(out);
@@ -49,13 +51,15 @@ class AndroidSecureRandomProvider extends LinuxSecureRandomProvider {
String id = Settings.Secure.getString(contentResolver, ANDROID_ID);
if (id != null) out.writeUTF(id);
Parcel parcel = Parcel.obtain();
WifiManager wm =
(WifiManager) appContext.getSystemService(WIFI_SERVICE);
WifiManager wm = (WifiManager) appContext.getApplicationContext()
.getSystemService(WIFI_SERVICE);
if (wm != null) {
List<WifiConfiguration> configs = wm.getConfiguredNetworks();
if (configs != null) {
for (WifiConfiguration config : configs)
parcel.writeParcelable(config, 0);
}
}
BluetoothAdapter bt = BluetoothAdapter.getDefaultAdapter();
if (bt != null) {
for (BluetoothDevice device : bt.getBondedDevices())
@@ -77,13 +81,13 @@ class AndroidSecureRandomProvider extends LinuxSecureRandomProvider {
// Based on https://android-developers.googleblog.com/2013/08/some-securerandom-thoughts.html
private void applyOpenSslFix() {
byte[] seed = new LinuxSecureRandomSpi().engineGenerateSeed(
byte[] seed = new UnixSecureRandomSpi().engineGenerateSeed(
SEED_LENGTH);
try {
// Seed the OpenSSL PRNG
Class.forName("org.apache.harmony.xnet.provider.jsse.NativeCrypto")
.getMethod("RAND_seed", byte[].class)
.invoke(null, seed);
.invoke(null, (Object) seed);
// Mix the output of the Linux PRNG into the OpenSSL PRNG
int bytesRead = (Integer) Class.forName(
"org.apache.harmony.xnet.provider.jsse.NativeCrypto")
@@ -11,15 +11,12 @@ import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import java.util.logging.Logger;
import static android.content.Context.MODE_PRIVATE;
import static android.os.Build.VERSION.SDK_INT;
public class AndroidUtils {
private static final Logger LOG =
Logger.getLogger(AndroidUtils.class.getName());
// Fake Bluetooth address returned by BluetoothAdapter on API 23 and later
private static final String FAKE_BLUETOOTH_ADDRESS = "02:00:00:00:00:00";
@@ -28,7 +25,7 @@ public class AndroidUtils {
@SuppressWarnings("deprecation")
public static Collection<String> getSupportedArchitectures() {
List<String> abis = new ArrayList<>();
if (Build.VERSION.SDK_INT >= 21) {
if (SDK_INT >= 21) {
abis.addAll(Arrays.asList(Build.SUPPORTED_ABIS));
} else {
abis.add(Build.CPU_ABI);
+11 -4
View File
@@ -31,16 +31,21 @@ dependencyVerification {
'com.android.tools:sdklib:26.2.1:sdklib-26.2.1.jar:248df7ad5eac4aeb6f96c394c76760de4b7b89ac056e54d0c21a739368b91b45',
'com.google.code.findbugs:jsr305:1.3.9:jsr305-1.3.9.jar:905721a0eea90a81534abb7ee6ef4ea2e5e645fa1def0a5cd88402df1b46c9ed',
'com.google.code.gson:gson:2.8.0:gson-2.8.0.jar:c6221763bd79c4f1c3dc7f750b5f29a0bb38b367b81314c4f71896e340c40825',
'com.google.dagger:dagger-compiler:2.0.2:dagger-compiler-2.0.2.jar:b74bc9de063dd4c6400b232231f2ef5056145b8fbecbf5382012007dd1c071b3',
'com.google.dagger:dagger-producers:2.0-beta:dagger-producers-2.0-beta.jar:99ec15e8a0507ba569e7655bc1165ee5e5ca5aa914b3c8f7e2c2458f724edd6b',
'com.google.dagger:dagger:2.0.2:dagger-2.0.2.jar:84c0282ed8be73a29e0475d639da030b55dee72369e58dd35ae7d4fe6243dcf9',
'com.google.dagger:dagger-compiler:2.19:dagger-compiler-2.19.jar:27a4b202a2de908182edb261f8c0a264e08e5e4733d7514bc7fbf0d31da5c0fc',
'com.google.dagger:dagger-producers:2.19:dagger-producers-2.19.jar:a17663abe0fc38b676026950907d4c5f5e2bf338375415861eaff6e3bdb0b768',
'com.google.dagger:dagger-spi:2.19:dagger-spi-2.19.jar:e7a6379d82c841f6aac2866948ad1eed716528707814602842a8d844ce04e2e1',
'com.google.dagger:dagger:2.19:dagger-2.19.jar:514b6f1e0727c6572e1d65cb27e4ae668b7aeaeb93a29515182965265b609939',
'com.google.errorprone:error_prone_annotations:2.0.18:error_prone_annotations-2.0.18.jar:cb4cfad870bf563a07199f3ebea5763f0dec440fcda0b318640b1feaa788656b',
'com.google.guava:guava:18.0:guava-18.0.jar:d664fbfc03d2e5ce9cab2a44fb01f1d0bf9dfebeccc1a473b1f9ea31f79f6f99',
'com.google.errorprone:error_prone_annotations:2.1.3:error_prone_annotations-2.1.3.jar:03d0329547c13da9e17c634d1049ea2ead093925e290567e1a364fd6b1fc7ff8',
'com.google.errorprone:javac-shaded:9-dev-r4023-3:javac-shaded-9-dev-r4023-3.jar:65bfccf60986c47fbc17c9ebab0be626afc41741e0a6ec7109e0768817a36f30',
'com.google.googlejavaformat:google-java-format:1.5:google-java-format-1.5.jar:aa19ad7850fb85178aa22f2fddb163b84d6ce4d0035872f30d4408195ca1144e',
'com.google.guava:guava:23.0:guava-23.0.jar:7baa80df284117e5b945b19b98d367a85ea7b7801bd358ff657946c3bd1b6596',
'com.google.guava:guava:25.0-jre:guava-25.0-jre.jar:3fd4341776428c7e0e5c18a7c10de129475b69ab9d30aeafbb5c277bb6074fa9',
'com.google.j2objc:j2objc-annotations:1.1:j2objc-annotations-1.1.jar:40ceb7157feb263949e0f503fe5f71689333a621021aa20ce0d0acee3badaa0f',
'com.google.jimfs:jimfs:1.1:jimfs-1.1.jar:c4828e28d7c0a930af9387510b3bada7daa5c04d7c25a75c7b8b081f1c257ddd',
'com.google.protobuf:protobuf-java:3.4.0:protobuf-java-3.4.0.jar:dce7e66b32456a1b1198da0caff3a8acb71548658391e798c79369241e6490a4',
'com.googlecode.json-simple:json-simple:1.1:json-simple-1.1.jar:2d9484f4c649f708f47f9a479465fc729770ee65617dca3011836602264f6439',
'com.squareup:javapoet:1.11.1:javapoet-1.11.1.jar:9cbf2107be499ec6e95afd36b58e3ca122a24166cdd375732e51267d64058e90',
'com.squareup:javawriter:2.5.0:javawriter-2.5.0.jar:fcfb09fb0ea0aa97d3cfe7ea792398081348e468f126b3603cb3803f240197f0',
'com.sun.activation:javax.activation:1.2.0:javax.activation-1.2.0.jar:993302b16cd7056f21e779cc577d175a810bb4900ef73cd8fbf2b50f928ba9ce',
'com.sun.istack:istack-commons-runtime:2.21:istack-commons-runtime-2.21.jar:c33e67a0807095f02a0e2da139412dd7c4f9cc1a4c054b3e434f96831ba950f4',
@@ -63,7 +68,9 @@ dependencyVerification {
'org.beanshell:bsh:1.3.0:bsh-1.3.0.jar:9b04edc75d19db54f1b4e8b5355e9364384c6cf71eb0a1b9724c159d779879f8',
'org.bouncycastle:bcpkix-jdk15on:1.56:bcpkix-jdk15on-1.56.jar:7043dee4e9e7175e93e0b36f45b1ec1ecb893c5f755667e8b916eb8dd201c6ca',
'org.bouncycastle:bcprov-jdk15on:1.56:bcprov-jdk15on-1.56.jar:963e1ee14f808ffb99897d848ddcdb28fa91ddda867eb18d303e82728f878349',
'org.briarproject:obfs4proxy-android:0.0.7:obfs4proxy-android-0.0.7.zip:abdfb5d889d848de9bf214f9276abbf454808a505b870819eccc9a9e985bf617',
'org.briarproject:tor-android:0.3.4.8:tor-android-0.3.4.8.zip:989a0352d9d8d8172cd6c2137654e165e5d2beb10ed1211bab3814e224ad1926',
'org.checkerframework:checker-compat-qual:2.5.3:checker-compat-qual-2.5.3.jar:d76b9afea61c7c082908023f0cbc1427fab9abd2df915c8b8a3e7a509bccbc6d',
'org.codehaus.groovy:groovy-all:2.4.12:groovy-all-2.4.12.jar:6a56af4bd48903d56bec62821876cadefafd007360cc6bd0d8f7aa8d72b38be4',
'org.codehaus.mojo:animal-sniffer-annotations:1.14:animal-sniffer-annotations-1.14.jar:2068320bd6bad744c3673ab048f67e30bef8f518996fa380033556600669905d',
'org.glassfish.jaxb:jaxb-core:2.2.11:jaxb-core-2.2.11.jar:37bcaee8ebb04362c8352a5bf6221b86967ecdab5164c696b10b9a2bb587b2aa',
+1 -3
View File
@@ -7,15 +7,13 @@ apply plugin: 'witness'
apply from: 'witness.gradle'
dependencies {
implementation "com.google.dagger:dagger:2.0.2"
implementation "com.google.dagger:dagger:2.19"
implementation 'com.google.code.findbugs:jsr305:3.0.2'
testImplementation 'junit:junit:4.12'
testImplementation "org.jmock:jmock:2.8.2"
testImplementation "org.jmock:jmock-junit4:2.8.2"
testImplementation "org.jmock:jmock-legacy:2.8.2"
testImplementation "org.hamcrest:hamcrest-library:1.3"
testImplementation "org.hamcrest:hamcrest-core:1.3"
signature 'org.codehaus.mojo.signature:java16:1.1@signature'
}
@@ -0,0 +1,26 @@
package org.briarproject.bramble.api;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import javax.annotation.concurrent.Immutable;
@Immutable
@NotNullByDefault
public class Pair<A, B> {
private final A first;
private final B second;
public Pair(A first, B second) {
this.first = first;
this.second = second;
}
public A getFirst() {
return first;
}
public B getSecond() {
return second;
}
}
@@ -0,0 +1,6 @@
package org.briarproject.bramble.api.battery;
public interface BatteryManager {
boolean isCharging();
}
@@ -0,0 +1,19 @@
package org.briarproject.bramble.api.battery.event;
import org.briarproject.bramble.api.event.Event;
/**
* An event that is broadcast when the device starts or stops charging.
*/
public class BatteryEvent extends Event {
private final boolean charging;
public BatteryEvent(boolean charging) {
this.charging = charging;
}
public boolean isCharging() {
return charging;
}
}
@@ -1,7 +1,6 @@
package org.briarproject.briar.client;
package org.briarproject.bramble.api.client;
import org.briarproject.bramble.api.FormatException;
import org.briarproject.bramble.api.client.ClientHelper;
import org.briarproject.bramble.api.data.BdfDictionary;
import org.briarproject.bramble.api.data.BdfList;
import org.briarproject.bramble.api.data.MetadataParser;
@@ -12,7 +11,7 @@ import org.briarproject.bramble.api.db.Transaction;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import org.briarproject.bramble.api.sync.InvalidMessageException;
import org.briarproject.bramble.api.sync.Message;
import org.briarproject.bramble.api.sync.ValidationManager.IncomingMessageHook;
import org.briarproject.bramble.api.sync.validation.IncomingMessageHook;
import javax.annotation.concurrent.Immutable;
@@ -62,5 +61,4 @@ public abstract class BdfIncomingMessageHook implements IncomingMessageHook {
throw new InvalidMessageException(e);
}
}
}
@@ -9,7 +9,7 @@ import org.briarproject.bramble.api.sync.Group;
import org.briarproject.bramble.api.sync.InvalidMessageException;
import org.briarproject.bramble.api.sync.Message;
import org.briarproject.bramble.api.sync.MessageContext;
import org.briarproject.bramble.api.sync.ValidationManager.MessageValidator;
import org.briarproject.bramble.api.sync.validation.MessageValidator;
import org.briarproject.bramble.api.system.Clock;
import java.util.logging.Logger;
@@ -13,6 +13,8 @@ import java.util.Collection;
import javax.annotation.Nullable;
import static org.briarproject.bramble.api.contact.PendingContact.PendingContactState.FAILED;
@NotNullByDefault
public interface ContactManager {
@@ -52,6 +54,35 @@ public interface ContactManager {
long timestamp, boolean alice, boolean verified, boolean active)
throws DbException;
/**
* Returns the static link that needs to be sent to the contact to be added.
*/
String getRemoteContactLink();
/**
* Returns true if the given link is syntactically valid.
*/
boolean isValidRemoteContactLink(String link);
/**
* Requests a new contact to be added via the given {@code link}.
*
* @param link The link received from the contact we want to add.
* @param alias The alias the user has given this contact.
* @return A PendingContact representing the contact to be added.
*/
PendingContact addRemoteContactRequest(String link, String alias);
/**
* Returns a list of {@link PendingContact}s.
*/
Collection<PendingContact> getPendingContacts();
/**
* Removes a {@link PendingContact} that is in state {@link FAILED}.
*/
void removePendingContact(PendingContact pendingContact);
/**
* Returns the contact with the given ID.
*/
@@ -96,6 +127,12 @@ public interface ContactManager {
void setContactActive(Transaction txn, ContactId c, boolean active)
throws DbException;
/**
* Sets an alias name for the contact or unsets it if alias is null.
*/
void setContactAlias(Transaction txn, ContactId c, @Nullable String alias)
throws DbException;
/**
* Sets an alias name for the contact or unsets it if alias is null.
*/
@@ -0,0 +1,54 @@
package org.briarproject.bramble.api.contact;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import javax.annotation.concurrent.Immutable;
@Immutable
@NotNullByDefault
public class PendingContact {
public enum PendingContactState {
WAITING_FOR_CONNECTION,
CONNECTED,
ADDING_CONTACT,
FAILED
}
private final PendingContactId id;
private final String alias;
private final PendingContactState state;
private final long timestamp;
public PendingContact(PendingContactId id, String alias,
PendingContactState state, long timestamp) {
this.id = id;
this.alias = alias;
this.state = state;
this.timestamp = timestamp;
}
public String getAlias() {
return alias;
}
public PendingContactState getState() {
return state;
}
public long getTimestamp() {
return timestamp;
}
@Override
public int hashCode() {
return id.hashCode();
}
@Override
public boolean equals(Object o) {
return o instanceof PendingContact &&
id.equals(((PendingContact) o).id);
}
}
@@ -0,0 +1,11 @@
package org.briarproject.bramble.api.contact;
import org.briarproject.bramble.api.UniqueId;
public class PendingContactId extends UniqueId {
public PendingContactId(byte[] id) {
super(id);
}
}
@@ -0,0 +1,34 @@
package org.briarproject.bramble.api.contact.event;
import org.briarproject.bramble.api.contact.PendingContact.PendingContactState;
import org.briarproject.bramble.api.contact.PendingContactId;
import org.briarproject.bramble.api.event.Event;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import javax.annotation.concurrent.Immutable;
/**
* An event that is broadcast when a pending contact's state is changed.
*/
@Immutable
@NotNullByDefault
public class PendingContactStateChangedEvent extends Event {
private final PendingContactId id;
private final PendingContactState state;
public PendingContactStateChangedEvent(PendingContactId id,
PendingContactState state) {
this.id = id;
this.state = state;
}
public PendingContactId getId() {
return id;
}
public PendingContactState getPendingContactState() {
return state;
}
}
@@ -0,0 +1,71 @@
package org.briarproject.bramble.api.data;
import org.briarproject.bramble.api.Bytes;
import org.briarproject.bramble.api.FormatException;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import javax.annotation.Nullable;
import static org.briarproject.bramble.api.data.BdfDictionary.NULL_VALUE;
import static org.briarproject.bramble.util.StringUtils.toHexString;
@NotNullByDefault
public class BdfStringUtils {
public static String toString(@Nullable Object o) throws FormatException {
return toString(o, 0);
}
private static String toString(@Nullable Object o, int indent)
throws FormatException {
if (o == null || o == NULL_VALUE) return "null";
if (o instanceof Boolean) return o.toString();
if (o instanceof Number) return o.toString();
if (o instanceof String) return "\"" + o + "\"";
if (o instanceof Bytes)
return "x" + toHexString(((Bytes) o).getBytes());
if (o instanceof byte[])
return "x" + toHexString((byte[]) o);
if (o instanceof List) {
List<?> list = (List) o;
StringBuilder sb = new StringBuilder();
sb.append("[\n");
int i = 0, size = list.size();
for (Object e : list) {
indent(sb, indent + 1);
sb.append(toString(e, indent + 1));
if (i++ < size - 1) sb.append(',');
sb.append('\n');
}
indent(sb, indent);
sb.append(']');
return sb.toString();
}
if (o instanceof Map) {
Map<?, ?> map = (Map) o;
StringBuilder sb = new StringBuilder();
sb.append("{\n");
int i = 0, size = map.size();
for (Entry e : map.entrySet()) {
indent(sb, indent + 1);
sb.append(toString(e.getKey(), indent + 1));
sb.append(": ");
sb.append(toString(e.getValue(), indent + 1));
if (i++ < size - 1) sb.append(',');
sb.append('\n');
}
indent(sb, indent);
sb.append('}');
return sb.toString();
}
throw new FormatException();
}
private static void indent(StringBuilder sb, int indent) {
for (int i = 0; i < indent; i++) sb.append('\t');
}
}
@@ -19,6 +19,7 @@ import org.briarproject.bramble.api.sync.MessageId;
import org.briarproject.bramble.api.sync.MessageStatus;
import org.briarproject.bramble.api.sync.Offer;
import org.briarproject.bramble.api.sync.Request;
import org.briarproject.bramble.api.sync.validation.MessageState;
import org.briarproject.bramble.api.transport.KeySet;
import org.briarproject.bramble.api.transport.KeySetId;
import org.briarproject.bramble.api.transport.TransportKeys;
@@ -28,8 +29,6 @@ import java.util.Map;
import javax.annotation.Nullable;
import static org.briarproject.bramble.api.sync.ValidationManager.State;
/**
* Encapsulates the database implementation and exposes high-level operations
* to other components.
@@ -89,6 +88,14 @@ public interface DatabaseComponent {
<R, E extends Exception> R transactionWithResult(boolean readOnly,
DbCallable<R, E> task) throws DbException, E;
/**
* Runs the given task within a transaction and returns the result of the
* task, which may be null.
*/
@Nullable
<R, E extends Exception> R transactionWithNullableResult(boolean readOnly,
NullableDbCallable<R, E> task) throws DbException, E;
/**
* Stores a contact associated with the given local and remote pseudonyms,
* and returns an ID for the contact.
@@ -366,12 +373,12 @@ public interface DatabaseComponent {
/**
* Returns the IDs and states of all dependencies of the given message.
* For missing dependencies and dependencies in other groups, the state
* {@link State UNKNOWN} is returned.
* {@link MessageState UNKNOWN} is returned.
* <p/>
* Read-only.
*/
Map<MessageId, State> getMessageDependencies(Transaction txn, MessageId m)
throws DbException;
Map<MessageId, MessageState> getMessageDependencies(Transaction txn,
MessageId m) throws DbException;
/**
* Returns the IDs and states of all dependents of the given message.
@@ -380,15 +387,16 @@ public interface DatabaseComponent {
* <p/>
* Read-only.
*/
Map<MessageId, State> getMessageDependents(Transaction txn, MessageId m)
throws DbException;
Map<MessageId, MessageState> getMessageDependents(Transaction txn,
MessageId m) throws DbException;
/**
* Gets the validation and delivery state of the given message.
* <p/>
* Read-only.
*/
State getMessageState(Transaction txn, MessageId m) throws DbException;
MessageState getMessageState(Transaction txn, MessageId m)
throws DbException;
/**
* Returns the status of the given delivered message with respect to the
@@ -535,7 +543,7 @@ public interface DatabaseComponent {
/**
* Sets the validation and delivery state of the given message.
*/
void setMessageState(Transaction txn, MessageId m, State state)
void setMessageState(Transaction txn, MessageId m, MessageState state)
throws DbException;
/**
@@ -1,5 +1,8 @@
package org.briarproject.bramble.api.db;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
@NotNullByDefault
public interface DbCallable<R, E extends Exception> {
R call(Transaction txn) throws DbException, E;
@@ -1,5 +1,8 @@
package org.briarproject.bramble.api.db;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
@NotNullByDefault
public interface DbRunnable<E extends Exception> {
void run(Transaction txn) throws DbException, E;
@@ -0,0 +1,12 @@
package org.briarproject.bramble.api.db;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import javax.annotation.Nullable;
@NotNullByDefault
public interface NullableDbCallable<R, E extends Exception> {
@Nullable
R call(Transaction txn) throws DbException, E;
}
@@ -10,7 +10,11 @@ import javax.annotation.concurrent.Immutable;
public class AuthorInfo {
public enum Status {
NONE, ANONYMOUS, UNKNOWN, UNVERIFIED, VERIFIED, OURSELVES
NONE, ANONYMOUS, UNKNOWN, UNVERIFIED, VERIFIED, OURSELVES;
public boolean isContact() {
return this == UNVERIFIED || this == VERIFIED;
}
}
private final Status status;
@@ -35,4 +39,18 @@ public class AuthorInfo {
return alias;
}
@Override
public int hashCode() {
int hashCode = status.ordinal();
if (alias != null) hashCode += alias.hashCode();
return hashCode;
}
@Override
public boolean equals(Object o) {
if (!(o instanceof AuthorInfo)) return false;
AuthorInfo info = (AuthorInfo) o;
return status == info.status &&
(alias == null ? info.alias == null : alias.equals(info.alias));
}
}
@@ -0,0 +1,15 @@
package org.briarproject.bramble.api.nullsafety;
import javax.annotation.Nullable;
@NotNullByDefault
public class NullSafety {
/**
* Stand-in for `Objects.requireNonNull()`.
*/
public static <T> T requireNonNull(@Nullable T t) {
if (t == null) throw new NullPointerException();
return t;
}
}
@@ -1,87 +0,0 @@
package org.briarproject.bramble.api.sync;
import org.briarproject.bramble.api.crypto.SecretKey;
import org.briarproject.bramble.api.db.DbException;
import org.briarproject.bramble.api.db.Metadata;
import org.briarproject.bramble.api.db.Transaction;
import org.briarproject.bramble.api.lifecycle.LifecycleManager;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
/**
* Responsible for managing message validators and passing them messages to
* validate.
*/
@NotNullByDefault
public interface ValidationManager {
enum State {
UNKNOWN(0), INVALID(1), PENDING(2), DELIVERED(3);
private final int value;
State(int value) {
this.value = value;
}
public int getValue() {
return value;
}
public static State fromValue(int value) {
for (State s : values()) if (s.value == value) return s;
throw new IllegalArgumentException();
}
}
/**
* Registers the message validator for the given client. This method
* should be called before
* {@link LifecycleManager#startServices(SecretKey)}.
*/
void registerMessageValidator(ClientId c, int majorVersion,
MessageValidator v);
/**
* Registers the incoming message hook for the given client. The hook will
* be called once for each incoming message that passes validation. This
* method should be called before
* {@link LifecycleManager#startServices(SecretKey)}.
*/
void registerIncomingMessageHook(ClientId c, int majorVersion,
IncomingMessageHook hook);
interface MessageValidator {
/**
* Validates the given message and returns its metadata and
* dependencies.
*/
MessageContext validateMessage(Message m, Group g)
throws InvalidMessageException;
}
interface IncomingMessageHook {
/**
* Called once for each incoming message that passes validation.
*
* @return whether or not this message should be shared
* @throws DbException Should only be used for real database errors.
* If this is thrown, delivery will be attempted again at next startup,
* whereas if an InvalidMessageException is thrown,
* the message will be permanently invalidated.
* @throws InvalidMessageException for any non-database error
* that occurs while handling remotely created data.
* This includes errors that occur while handling locally created data
* in a context controlled by remotely created data
* (for example, parsing the metadata of a dependency
* of an incoming message).
* Throwing this will delete the incoming message and its metadata
* marking it as invalid in the database.
* Never rethrow DbException as InvalidMessageException!
*/
boolean incomingMessage(Transaction txn, Message m, Metadata meta)
throws DbException, InvalidMessageException;
}
}
@@ -3,11 +3,10 @@ package org.briarproject.bramble.api.sync.event;
import org.briarproject.bramble.api.event.Event;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import org.briarproject.bramble.api.sync.MessageId;
import org.briarproject.bramble.api.sync.validation.MessageState;
import javax.annotation.concurrent.Immutable;
import static org.briarproject.bramble.api.sync.ValidationManager.State;
/**
* An event that is broadcast when a message state changed.
*/
@@ -17,10 +16,10 @@ public class MessageStateChangedEvent extends Event {
private final MessageId messageId;
private final boolean local;
private final State state;
private final MessageState state;
public MessageStateChangedEvent(MessageId messageId, boolean local,
State state) {
MessageState state) {
this.messageId = messageId;
this.local = local;
this.state = state;
@@ -34,7 +33,7 @@ public class MessageStateChangedEvent extends Event {
return local;
}
public State getState() {
public MessageState getState() {
return state;
}
@@ -0,0 +1,31 @@
package org.briarproject.bramble.api.sync.validation;
import org.briarproject.bramble.api.db.DbException;
import org.briarproject.bramble.api.db.Metadata;
import org.briarproject.bramble.api.db.Transaction;
import org.briarproject.bramble.api.sync.InvalidMessageException;
import org.briarproject.bramble.api.sync.Message;
public interface IncomingMessageHook {
/**
* Called once for each incoming message that passes validation.
*
* @return whether or not this message should be shared
* @throws DbException Should only be used for real database errors.
* If this is thrown, delivery will be attempted again at next startup,
* whereas if an InvalidMessageException is thrown,
* the message will be permanently invalidated.
* @throws InvalidMessageException for any non-database error
* that occurs while handling remotely created data.
* This includes errors that occur while handling locally created data
* in a context controlled by remotely created data
* (for example, parsing the metadata of a dependency
* of an incoming message).
* Throwing this will delete the incoming message and its metadata
* marking it as invalid in the database.
* Never rethrow DbException as InvalidMessageException!
*/
boolean incomingMessage(Transaction txn, Message m, Metadata meta)
throws DbException, InvalidMessageException;
}
@@ -0,0 +1,21 @@
package org.briarproject.bramble.api.sync.validation;
public enum MessageState {
UNKNOWN(0), INVALID(1), PENDING(2), DELIVERED(3);
private final int value;
MessageState(int value) {
this.value = value;
}
public int getValue() {
return value;
}
public static MessageState fromValue(int value) {
for (MessageState s : values()) if (s.value == value) return s;
throw new IllegalArgumentException();
}
}
@@ -0,0 +1,16 @@
package org.briarproject.bramble.api.sync.validation;
import org.briarproject.bramble.api.sync.Group;
import org.briarproject.bramble.api.sync.InvalidMessageException;
import org.briarproject.bramble.api.sync.Message;
import org.briarproject.bramble.api.sync.MessageContext;
public interface MessageValidator {
/**
* Validates the given message and returns its metadata and
* dependencies.
*/
MessageContext validateMessage(Message m, Group g)
throws InvalidMessageException;
}
@@ -0,0 +1,31 @@
package org.briarproject.bramble.api.sync.validation;
import org.briarproject.bramble.api.crypto.SecretKey;
import org.briarproject.bramble.api.lifecycle.LifecycleManager;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import org.briarproject.bramble.api.sync.ClientId;
/**
* Responsible for managing message validators and passing them messages to
* validate.
*/
@NotNullByDefault
public interface ValidationManager {
/**
* Registers the {@link MessageValidator} for the given client. This method
* should be called before
* {@link LifecycleManager#startServices(SecretKey)}.
*/
void registerMessageValidator(ClientId c, int majorVersion,
MessageValidator v);
/**
* Registers the {@link IncomingMessageHook} for the given client. The hook
* will be called once for each incoming message that passes validation.
* This method should be called before
* {@link LifecycleManager#startServices(SecretKey)}.
*/
void registerIncomingMessageHook(ClientId c, int majorVersion,
IncomingMessageHook hook);
}
@@ -38,6 +38,13 @@ public interface ClientVersioningManager {
Visibility getClientVisibility(Transaction txn, ContactId contactId,
ClientId clientId, int majorVersion) throws DbException;
/**
* Returns the minor version of the given client that is supported by the
* given contact, or -1 if the contact does not support the client.
*/
int getClientMinorVersion(Transaction txn, ContactId contactId,
ClientId clientId, int majorVersion) throws DbException;
interface ClientVersioningHook {
void onClientVisibilityChanging(Transaction txn, Contact c,
@@ -8,12 +8,15 @@ import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.annotation.Nullable;
import static java.util.logging.Level.WARNING;
import static org.briarproject.bramble.util.LogUtils.logException;
@NotNullByDefault
public class IoUtils {
@@ -54,16 +57,35 @@ public class IoUtils {
out.flush();
out.close();
} catch (IOException e) {
tryToClose(in);
tryToClose(out);
tryToClose(in, LOG, WARNING);
tryToClose(out, LOG, WARNING);
}
}
private static void tryToClose(@Nullable Closeable c) {
public static void tryToClose(@Nullable Closeable c, Logger logger,
Level level) {
try {
if (c != null) c.close();
} catch (IOException e) {
// We did our best
logException(logger, level, e);
}
}
public static void tryToClose(@Nullable Socket s, Logger logger,
Level level) {
try {
if (s != null) s.close();
} catch (IOException e) {
logException(logger, level, e);
}
}
public static void tryToClose(@Nullable ServerSocket ss, Logger logger,
Level level) {
try {
if (ss != null) ss.close();
} catch (IOException e) {
logException(logger, level, e);
}
}
@@ -10,8 +10,6 @@ public class OsUtils {
@Nullable
private static final String os = System.getProperty("os.name");
@Nullable
private static final String version = System.getProperty("os.version");
@Nullable
private static final String vendor = System.getProperty("java.vendor");
public static boolean isWindows() {
@@ -47,7 +47,7 @@ public class StringUtils {
try {
return s.getBytes("UTF-8");
} catch (UnsupportedEncodingException e) {
throw new RuntimeException(e);
throw new AssertionError(e);
}
}
@@ -63,7 +63,7 @@ public class StringUtils {
try {
return decoder.decode(buffer).toString();
} catch (CharacterCodingException e) {
throw new RuntimeException(e);
throw new AssertionError(e);
}
}
@@ -0,0 +1,42 @@
package org.briarproject.bramble.api.identity;
import org.briarproject.bramble.test.BrambleTestCase;
import org.junit.Test;
import static org.briarproject.bramble.api.identity.AuthorInfo.Status.NONE;
import static org.briarproject.bramble.api.identity.AuthorInfo.Status.VERIFIED;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotEquals;
public class AuthorInfoTest extends BrambleTestCase {
@Test
public void testEquals() {
assertEquals(
new AuthorInfo(NONE),
new AuthorInfo(NONE, null)
);
assertEquals(
new AuthorInfo(NONE, "test"),
new AuthorInfo(NONE, "test")
);
assertNotEquals(
new AuthorInfo(NONE),
new AuthorInfo(VERIFIED)
);
assertNotEquals(
new AuthorInfo(NONE, "test"),
new AuthorInfo(NONE)
);
assertNotEquals(
new AuthorInfo(NONE),
new AuthorInfo(NONE, "test")
);
assertNotEquals(
new AuthorInfo(NONE, "a"),
new AuthorInfo(NONE, "b")
);
}
}
+1 -1
View File
@@ -2,7 +2,7 @@ dependencyVerification {
verify = [
'cglib:cglib:3.2.0:cglib-3.2.0.jar:adb13bab79712ad6bdf1bd59f2a3918018a8016e722e8a357065afb9e6690861',
'com.google.code.findbugs:jsr305:3.0.2:jsr305-3.0.2.jar:766ad2a0783f2687962c8ad74ceecc38a28b9f72a2d085ee438b7813e928d0c7',
'com.google.dagger:dagger:2.0.2:dagger-2.0.2.jar:84c0282ed8be73a29e0475d639da030b55dee72369e58dd35ae7d4fe6243dcf9',
'com.google.dagger:dagger:2.19:dagger-2.19.jar:514b6f1e0727c6572e1d65cb27e4ae668b7aeaeb93a29515182965265b609939',
'javax.inject:javax.inject:1:javax.inject-1.jar:91c77044a50c481636c32d916fd89c9118a72195390452c81065080f957de7ff',
'junit:junit:4.12:junit-4.12.jar:59721f0805e223d84b90677887d9ff567dc534d7c502ca903c0c2b17f05c116a',
'org.apache.ant:ant-launcher:1.9.4:ant-launcher-1.9.4.jar:7bccea20b41801ca17bcbc909a78c835d0f443f12d639c77bd6ae3d05861608d',
+3 -5
View File
@@ -3,10 +3,10 @@ sourceCompatibility = 1.8
targetCompatibility = 1.8
apply plugin: 'ru.vyarus.animalsniffer'
apply plugin: 'net.ltgt.apt'
apply plugin: 'idea'
apply plugin: 'witness'
apply from: 'witness.gradle'
apply from: '../dagger.gradle'
dependencies {
implementation project(path: ':bramble-api', configuration: 'default')
@@ -17,7 +17,7 @@ dependencies {
implementation 'org.whispersystems:curve25519-java:0.5.0'
implementation 'org.briarproject:jtorctl:0.3'
apt 'com.google.dagger:dagger-compiler:2.0.2'
annotationProcessor 'com.google.dagger:dagger-compiler:2.19'
testImplementation project(path: ':bramble-api', configuration: 'testOutput')
testImplementation 'org.hsqldb:hsqldb:2.3.5' // The last version that supports Java 1.6
@@ -25,10 +25,8 @@ dependencies {
testImplementation "org.jmock:jmock:2.8.2"
testImplementation "org.jmock:jmock-junit4:2.8.2"
testImplementation "org.jmock:jmock-legacy:2.8.2"
testImplementation "org.hamcrest:hamcrest-library:1.3"
testImplementation "org.hamcrest:hamcrest-core:1.3"
testApt 'com.google.dagger:dagger-compiler:2.0.2'
testAnnotationProcessor 'com.google.dagger:dagger-compiler:2.19'
signature 'org.codehaus.mojo.signature:java16:1.1@signature'
}
@@ -8,7 +8,7 @@ import org.briarproject.bramble.lifecycle.LifecycleModule;
import org.briarproject.bramble.plugin.PluginModule;
import org.briarproject.bramble.properties.PropertiesModule;
import org.briarproject.bramble.reporting.ReportingModule;
import org.briarproject.bramble.sync.SyncModule;
import org.briarproject.bramble.sync.validation.ValidationModule;
import org.briarproject.bramble.system.SystemModule;
import org.briarproject.bramble.transport.TransportModule;
import org.briarproject.bramble.versioning.VersioningModule;
@@ -31,11 +31,11 @@ public interface BrambleCoreEagerSingletons {
void inject(ReportingModule.EagerSingletons init);
void inject(SyncModule.EagerSingletons init);
void inject(SystemModule.EagerSingletons init);
void inject(TransportModule.EagerSingletons init);
void inject(ValidationModule.EagerSingletons init);
void inject(VersioningModule.EagerSingletons init);
}
@@ -19,6 +19,7 @@ import org.briarproject.bramble.reporting.ReportingModule;
import org.briarproject.bramble.settings.SettingsModule;
import org.briarproject.bramble.socks.SocksModule;
import org.briarproject.bramble.sync.SyncModule;
import org.briarproject.bramble.sync.validation.ValidationModule;
import org.briarproject.bramble.system.SystemModule;
import org.briarproject.bramble.transport.TransportModule;
import org.briarproject.bramble.versioning.VersioningModule;
@@ -47,6 +48,7 @@ import dagger.Module;
SyncModule.class,
SystemModule.class,
TransportModule.class,
ValidationModule.class,
VersioningModule.class
})
public class BrambleCoreModule {
@@ -60,9 +62,9 @@ public class BrambleCoreModule {
c.inject(new PluginModule.EagerSingletons());
c.inject(new PropertiesModule.EagerSingletons());
c.inject(new ReportingModule.EagerSingletons());
c.inject(new SyncModule.EagerSingletons());
c.inject(new SystemModule.EagerSingletons());
c.inject(new TransportModule.EagerSingletons());
c.inject(new ValidationModule.EagerSingletons());
c.inject(new VersioningModule.EagerSingletons());
}
}
@@ -0,0 +1,19 @@
package org.briarproject.bramble.battery;
import org.briarproject.bramble.api.battery.BatteryManager;
import dagger.Module;
import dagger.Provides;
/**
* Provides a default implementation of {@link BatteryManager} for systems
* without batteries.
*/
@Module
public class DefaultBatteryManagerModule {
@Provides
BatteryManager provideBatteryManager() {
return () -> false;
}
}
@@ -82,13 +82,7 @@ class ClientHelperImpl implements ClientHelper {
@Override
public void addLocalMessage(Message m, BdfDictionary metadata,
boolean shared) throws DbException, FormatException {
Transaction txn = db.startTransaction(false);
try {
addLocalMessage(txn, m, metadata, shared);
db.commitTransaction(txn);
} finally {
db.endTransaction(txn);
}
db.transaction(false, txn -> addLocalMessage(txn, m, metadata, shared));
}
@Override
@@ -113,15 +107,7 @@ class ClientHelperImpl implements ClientHelper {
@Override
public Message getMessage(MessageId m) throws DbException {
Message message;
Transaction txn = db.startTransaction(true);
try {
message = getMessage(txn, m);
db.commitTransaction(txn);
} finally {
db.endTransaction(txn);
}
return message;
return db.transactionWithResult(true, txn -> getMessage(txn, m));
}
@Override
@@ -132,15 +118,7 @@ class ClientHelperImpl implements ClientHelper {
@Override
public BdfList getMessageAsList(MessageId m) throws DbException,
FormatException {
BdfList list;
Transaction txn = db.startTransaction(true);
try {
list = getMessageAsList(txn, m);
db.commitTransaction(txn);
} finally {
db.endTransaction(txn);
}
return list;
return db.transactionWithResult(true, txn -> getMessageAsList(txn, m));
}
@Override
@@ -152,15 +130,8 @@ class ClientHelperImpl implements ClientHelper {
@Override
public BdfDictionary getGroupMetadataAsDictionary(GroupId g)
throws DbException, FormatException {
BdfDictionary dictionary;
Transaction txn = db.startTransaction(true);
try {
dictionary = getGroupMetadataAsDictionary(txn, g);
db.commitTransaction(txn);
} finally {
db.endTransaction(txn);
}
return dictionary;
return db.transactionWithResult(true, txn ->
getGroupMetadataAsDictionary(txn, g));
}
@Override
@@ -173,15 +144,8 @@ class ClientHelperImpl implements ClientHelper {
@Override
public BdfDictionary getMessageMetadataAsDictionary(MessageId m)
throws DbException, FormatException {
BdfDictionary dictionary;
Transaction txn = db.startTransaction(true);
try {
dictionary = getMessageMetadataAsDictionary(txn, m);
db.commitTransaction(txn);
} finally {
db.endTransaction(txn);
}
return dictionary;
return db.transactionWithResult(true, txn ->
getMessageMetadataAsDictionary(txn, m));
}
@Override
@@ -194,15 +158,8 @@ class ClientHelperImpl implements ClientHelper {
@Override
public Map<MessageId, BdfDictionary> getMessageMetadataAsDictionary(
GroupId g) throws DbException, FormatException {
Map<MessageId, BdfDictionary> map;
Transaction txn = db.startTransaction(true);
try {
map = getMessageMetadataAsDictionary(txn, g);
db.commitTransaction(txn);
} finally {
db.endTransaction(txn);
}
return map;
return db.transactionWithResult(true, txn ->
getMessageMetadataAsDictionary(txn, g));
}
@Override
@@ -219,15 +176,8 @@ class ClientHelperImpl implements ClientHelper {
public Map<MessageId, BdfDictionary> getMessageMetadataAsDictionary(
GroupId g, BdfDictionary query) throws DbException,
FormatException {
Map<MessageId, BdfDictionary> map;
Transaction txn = db.startTransaction(true);
try {
map = getMessageMetadataAsDictionary(txn, g, query);
db.commitTransaction(txn);
} finally {
db.endTransaction(txn);
}
return map;
return db.transactionWithResult(true, txn ->
getMessageMetadataAsDictionary(txn, g, query));
}
@Override
@@ -245,13 +195,7 @@ class ClientHelperImpl implements ClientHelper {
@Override
public void mergeGroupMetadata(GroupId g, BdfDictionary metadata)
throws DbException, FormatException {
Transaction txn = db.startTransaction(false);
try {
mergeGroupMetadata(txn, g, metadata);
db.commitTransaction(txn);
} finally {
db.endTransaction(txn);
}
db.transaction(false, txn -> mergeGroupMetadata(txn, g, metadata));
}
@Override
@@ -263,13 +207,7 @@ class ClientHelperImpl implements ClientHelper {
@Override
public void mergeMessageMetadata(MessageId m, BdfDictionary metadata)
throws DbException, FormatException {
Transaction txn = db.startTransaction(false);
try {
mergeMessageMetadata(txn, m, metadata);
db.commitTransaction(txn);
} finally {
db.endTransaction(txn);
}
db.transaction(false, txn -> mergeMessageMetadata(txn, m, metadata));
}
@Override
@@ -13,7 +13,6 @@ import org.briarproject.bramble.api.data.BdfList;
import org.briarproject.bramble.api.db.ContactExistsException;
import org.briarproject.bramble.api.db.DatabaseComponent;
import org.briarproject.bramble.api.db.DbException;
import org.briarproject.bramble.api.db.Transaction;
import org.briarproject.bramble.api.identity.Author;
import org.briarproject.bramble.api.identity.LocalAuthor;
import org.briarproject.bramble.api.nullsafety.MethodsNotNullByDefault;
@@ -158,7 +157,8 @@ class ContactExchangeTaskImpl extends Thread implements ContactExchangeTask {
streamWriterFactory.createContactExchangeStreamWriter(out,
alice ? aliceHeaderKey : bobHeaderKey);
RecordWriter recordWriter =
recordWriterFactory.createRecordWriter(streamWriter.getOutputStream());
recordWriterFactory
.createRecordWriter(streamWriter.getOutputStream());
// Derive the nonces to be signed
byte[] aliceNonce = crypto.mac(ALICE_NONCE_LABEL, masterSecret,
@@ -287,19 +287,14 @@ class ContactExchangeTaskImpl extends Thread implements ContactExchangeTask {
private ContactId addContact(Author remoteAuthor, long timestamp,
Map<TransportId, TransportProperties> remoteProperties)
throws DbException {
ContactId contactId;
Transaction txn = db.startTransaction(false);
try {
contactId = contactManager.addContact(txn, remoteAuthor,
return db.transactionWithResult(false, txn -> {
ContactId contactId = contactManager.addContact(txn, remoteAuthor,
localAuthor.getId(), masterSecret, timestamp, alice,
true, true);
transportPropertyManager.addRemoteProperties(txn, contactId,
remoteProperties);
db.commitTransaction(txn);
} finally {
db.endTransaction(txn);
}
return contactId;
});
}
private void tryToClose(DuplexTransportConnection conn) {
@@ -3,6 +3,8 @@ package org.briarproject.bramble.contact;
import org.briarproject.bramble.api.contact.Contact;
import org.briarproject.bramble.api.contact.ContactId;
import org.briarproject.bramble.api.contact.ContactManager;
import org.briarproject.bramble.api.contact.PendingContact;
import org.briarproject.bramble.api.contact.PendingContactId;
import org.briarproject.bramble.api.crypto.SecretKey;
import org.briarproject.bramble.api.db.DatabaseComponent;
import org.briarproject.bramble.api.db.DbException;
@@ -19,12 +21,16 @@ import org.briarproject.bramble.api.transport.KeyManager;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Random;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.regex.Pattern;
import javax.annotation.Nullable;
import javax.annotation.concurrent.ThreadSafe;
import javax.inject.Inject;
import static java.util.Collections.emptyList;
import static org.briarproject.bramble.api.contact.PendingContact.PendingContactState.WAITING_FOR_CONNECTION;
import static org.briarproject.bramble.api.identity.AuthorConstants.MAX_AUTHOR_NAME_LENGTH;
import static org.briarproject.bramble.api.identity.AuthorInfo.Status.OURSELVES;
import static org.briarproject.bramble.api.identity.AuthorInfo.Status.UNKNOWN;
@@ -36,6 +42,12 @@ import static org.briarproject.bramble.util.StringUtils.toUtf8;
@NotNullByDefault
class ContactManagerImpl implements ContactManager {
private static final int LINK_LENGTH = 64;
private static final String REMOTE_CONTACT_LINK =
"briar://" + getRandomBase32String(LINK_LENGTH);
private static final Pattern LINK_REGEX =
Pattern.compile("(briar://)?([a-z2-7]{" + LINK_LENGTH + "})");
private final DatabaseComponent db;
private final KeyManager keyManager;
private final IdentityManager identityManager;
@@ -79,42 +91,63 @@ class ContactManagerImpl implements ContactManager {
public ContactId addContact(Author remote, AuthorId local, SecretKey master,
long timestamp, boolean alice, boolean verified, boolean active)
throws DbException {
ContactId c;
Transaction txn = db.startTransaction(false);
try {
c = addContact(txn, remote, local, master, timestamp, alice,
verified, active);
db.commitTransaction(txn);
} finally {
db.endTransaction(txn);
return db.transactionWithResult(false, txn ->
addContact(txn, remote, local, master, timestamp, alice,
verified, active));
}
return c;
@Override
public String getRemoteContactLink() {
// TODO replace with real implementation
return REMOTE_CONTACT_LINK;
}
@SuppressWarnings("SameParameterValue")
private static String getRandomBase32String(int length) {
Random random = new Random();
char[] c = new char[length];
for (int i = 0; i < length; i++) {
int character = random.nextInt(32);
if (character < 26) c[i] = (char) ('a' + character);
else c[i] = (char) ('2' + (character - 26));
}
return new String(c);
}
@Override
public boolean isValidRemoteContactLink(String link) {
return LINK_REGEX.matcher(link).matches();
}
@Override
public PendingContact addRemoteContactRequest(String link, String alias) {
// TODO replace with real implementation
PendingContactId id = new PendingContactId(link.getBytes());
return new PendingContact(id, alias, WAITING_FOR_CONNECTION,
System.currentTimeMillis());
}
@Override
public Collection<PendingContact> getPendingContacts() {
// TODO replace with real implementation
return emptyList();
}
@Override
public void removePendingContact(PendingContact pendingContact) {
// TODO replace with real implementation
}
@Override
public Contact getContact(ContactId c) throws DbException {
Contact contact;
Transaction txn = db.startTransaction(true);
try {
contact = db.getContact(txn, c);
db.commitTransaction(txn);
} finally {
db.endTransaction(txn);
}
return contact;
return db.transactionWithResult(true, txn -> db.getContact(txn, c));
}
@Override
public Contact getContact(AuthorId remoteAuthorId, AuthorId localAuthorId)
throws DbException {
Transaction txn = db.startTransaction(true);
try {
Contact c = getContact(txn, remoteAuthorId, localAuthorId);
db.commitTransaction(txn);
return c;
} finally {
db.endTransaction(txn);
}
return db.transactionWithResult(true, txn ->
getContact(txn, remoteAuthorId, localAuthorId));
}
@Override
@@ -132,14 +165,8 @@ class ContactManagerImpl implements ContactManager {
@Override
public Collection<Contact> getActiveContacts() throws DbException {
Collection<Contact> contacts;
Transaction txn = db.startTransaction(true);
try {
contacts = db.getContacts(txn);
db.commitTransaction(txn);
} finally {
db.endTransaction(txn);
}
Collection<Contact> contacts =
db.transactionWithResult(true, db::getContacts);
List<Contact> active = new ArrayList<>(contacts.size());
for (Contact c : contacts) if (c.isActive()) active.add(c);
return active;
@@ -147,13 +174,7 @@ class ContactManagerImpl implements ContactManager {
@Override
public void removeContact(ContactId c) throws DbException {
Transaction txn = db.startTransaction(false);
try {
removeContact(txn, c);
db.commitTransaction(txn);
} finally {
db.endTransaction(txn);
}
db.transaction(false, txn -> removeContact(txn, c));
}
@Override
@@ -163,14 +184,20 @@ class ContactManagerImpl implements ContactManager {
}
@Override
public void setContactAlias(ContactId c, @Nullable String alias)
throws DbException {
public void setContactAlias(Transaction txn, ContactId c,
@Nullable String alias) throws DbException {
if (alias != null) {
int aliasLength = toUtf8(alias).length;
if (aliasLength == 0 || aliasLength > MAX_AUTHOR_NAME_LENGTH)
throw new IllegalArgumentException();
}
db.transaction(false, txn -> db.setContactAlias(txn, c, alias));
db.setContactAlias(txn, c, alias);
}
@Override
public void setContactAlias(ContactId c, @Nullable String alias)
throws DbException {
db.transaction(false, txn -> setContactAlias(txn, c, alias));
}
@Override
@@ -182,15 +209,8 @@ class ContactManagerImpl implements ContactManager {
@Override
public boolean contactExists(AuthorId remoteAuthorId,
AuthorId localAuthorId) throws DbException {
boolean exists;
Transaction txn = db.startTransaction(true);
try {
exists = contactExists(txn, remoteAuthorId, localAuthorId);
db.commitTransaction(txn);
} finally {
db.endTransaction(txn);
}
return exists;
return db.transactionWithResult(true, txn ->
contactExists(txn, remoteAuthorId, localAuthorId));
}
@Override
@@ -29,6 +29,7 @@ import static org.briarproject.bramble.data.Types.STRING_16;
import static org.briarproject.bramble.data.Types.STRING_32;
import static org.briarproject.bramble.data.Types.STRING_8;
import static org.briarproject.bramble.data.Types.TRUE;
import static org.briarproject.bramble.util.StringUtils.fromUtf8;
@NotThreadSafe
@NotNullByDefault
@@ -253,7 +254,7 @@ class BdfReaderImpl implements BdfReader {
if (length < 0 || length > maxBufferSize) throw new FormatException();
if (length == 0) return "";
readIntoBuffer(length);
return new String(buf, 0, length, "UTF-8");
return fromUtf8(buf, 0, length);
}
private int readStringLength() throws IOException {
@@ -22,7 +22,7 @@ import org.briarproject.bramble.api.sync.GroupId;
import org.briarproject.bramble.api.sync.Message;
import org.briarproject.bramble.api.sync.MessageId;
import org.briarproject.bramble.api.sync.MessageStatus;
import org.briarproject.bramble.api.sync.ValidationManager.State;
import org.briarproject.bramble.api.sync.validation.MessageState;
import org.briarproject.bramble.api.transport.KeySet;
import org.briarproject.bramble.api.transport.KeySetId;
import org.briarproject.bramble.api.transport.TransportKeys;
@@ -106,7 +106,7 @@ interface Database<T> {
* @param sender the contact from whom the message was received, or null
* if the message was created locally.
*/
void addMessage(T txn, Message m, State state, boolean shared,
void addMessage(T txn, Message m, MessageState state, boolean shared,
@Nullable ContactId sender) throws DbException;
/**
@@ -114,7 +114,7 @@ interface Database<T> {
* in the given state.
*/
void addMessageDependency(T txn, Message dependent, MessageId dependency,
State dependentState) throws DbException;
MessageState dependentState) throws DbException;
/**
* Records that a message has been offered by the given contact.
@@ -310,11 +310,11 @@ interface Database<T> {
/**
* Returns the IDs and states of all dependencies of the given message.
* For missing dependencies and dependencies in other groups, the state
* {@link State UNKNOWN} is returned.
* {@link MessageState UNKNOWN} is returned.
* <p/>
* Read-only.
*/
Map<MessageId, State> getMessageDependencies(T txn, MessageId m)
Map<MessageId, MessageState> getMessageDependencies(T txn, MessageId m)
throws DbException;
/**
@@ -324,7 +324,7 @@ interface Database<T> {
* <p/>
* Read-only.
*/
Map<MessageId, State> getMessageDependents(T txn, MessageId m)
Map<MessageId, MessageState> getMessageDependents(T txn, MessageId m)
throws DbException;
/**
@@ -383,7 +383,7 @@ interface Database<T> {
* <p/>
* Read-only.
*/
State getMessageState(T txn, MessageId m) throws DbException;
MessageState getMessageState(T txn, MessageId m) throws DbException;
/**
* Returns the status of all delivered messages in the given group with
@@ -637,7 +637,8 @@ interface Database<T> {
/**
* Sets the validation and delivery state of the given message.
*/
void setMessageState(T txn, MessageId m, State state) throws DbException;
void setMessageState(T txn, MessageId m, MessageState state)
throws DbException;
/**
* Sets the reordering window for the given key set and transport in the
@@ -19,6 +19,7 @@ import org.briarproject.bramble.api.db.NoSuchGroupException;
import org.briarproject.bramble.api.db.NoSuchLocalAuthorException;
import org.briarproject.bramble.api.db.NoSuchMessageException;
import org.briarproject.bramble.api.db.NoSuchTransportException;
import org.briarproject.bramble.api.db.NullableDbCallable;
import org.briarproject.bramble.api.db.Transaction;
import org.briarproject.bramble.api.event.Event;
import org.briarproject.bramble.api.event.EventBus;
@@ -42,7 +43,6 @@ import org.briarproject.bramble.api.sync.MessageId;
import org.briarproject.bramble.api.sync.MessageStatus;
import org.briarproject.bramble.api.sync.Offer;
import org.briarproject.bramble.api.sync.Request;
import org.briarproject.bramble.api.sync.ValidationManager.State;
import org.briarproject.bramble.api.sync.event.GroupAddedEvent;
import org.briarproject.bramble.api.sync.event.GroupRemovedEvent;
import org.briarproject.bramble.api.sync.event.GroupVisibilityUpdatedEvent;
@@ -54,6 +54,7 @@ import org.briarproject.bramble.api.sync.event.MessageToAckEvent;
import org.briarproject.bramble.api.sync.event.MessageToRequestEvent;
import org.briarproject.bramble.api.sync.event.MessagesAckedEvent;
import org.briarproject.bramble.api.sync.event.MessagesSentEvent;
import org.briarproject.bramble.api.sync.validation.MessageState;
import org.briarproject.bramble.api.transport.KeySet;
import org.briarproject.bramble.api.transport.KeySetId;
import org.briarproject.bramble.api.transport.TransportKeys;
@@ -74,8 +75,8 @@ import javax.inject.Inject;
import static java.util.logging.Level.WARNING;
import static org.briarproject.bramble.api.sync.Group.Visibility.INVISIBLE;
import static org.briarproject.bramble.api.sync.Group.Visibility.SHARED;
import static org.briarproject.bramble.api.sync.ValidationManager.State.DELIVERED;
import static org.briarproject.bramble.api.sync.ValidationManager.State.UNKNOWN;
import static org.briarproject.bramble.api.sync.validation.MessageState.DELIVERED;
import static org.briarproject.bramble.api.sync.validation.MessageState.UNKNOWN;
import static org.briarproject.bramble.db.DatabaseConstants.MAX_OFFERED_MESSAGES;
import static org.briarproject.bramble.util.LogUtils.logDuration;
import static org.briarproject.bramble.util.LogUtils.logException;
@@ -193,6 +194,20 @@ class DatabaseComponentImpl<T> implements DatabaseComponent {
}
}
@Override
public <R, E extends Exception> R transactionWithNullableResult(
boolean readOnly, NullableDbCallable<R, E> task)
throws DbException, E {
Transaction txn = startTransaction(readOnly);
try {
R result = task.call(txn);
commitTransaction(txn);
return result;
} finally {
endTransaction(txn);
}
}
private T unbox(Transaction transaction) {
if (transaction.isCommitted()) throw new IllegalStateException();
return txnClass.cast(transaction.unbox());
@@ -564,7 +579,7 @@ class DatabaseComponentImpl<T> implements DatabaseComponent {
}
@Override
public State getMessageState(Transaction transaction, MessageId m)
public MessageState getMessageState(Transaction transaction, MessageId m)
throws DbException {
T txn = unbox(transaction);
if (!db.containsMessage(txn, m))
@@ -604,8 +619,8 @@ class DatabaseComponentImpl<T> implements DatabaseComponent {
}
@Override
public Map<MessageId, State> getMessageDependencies(Transaction transaction,
MessageId m) throws DbException {
public Map<MessageId, MessageState> getMessageDependencies(
Transaction transaction, MessageId m) throws DbException {
T txn = unbox(transaction);
if (!db.containsMessage(txn, m))
throw new NoSuchMessageException();
@@ -613,8 +628,8 @@ class DatabaseComponentImpl<T> implements DatabaseComponent {
}
@Override
public Map<MessageId, State> getMessageDependents(Transaction transaction,
MessageId m) throws DbException {
public Map<MessageId, MessageState> getMessageDependents(
Transaction transaction, MessageId m) throws DbException {
T txn = unbox(transaction);
if (!db.containsMessage(txn, m))
throw new NoSuchMessageException();
@@ -861,7 +876,7 @@ class DatabaseComponentImpl<T> implements DatabaseComponent {
@Override
public void setContactAlias(Transaction transaction, ContactId c,
String alias) throws DbException {
@Nullable String alias) throws DbException {
if (transaction.isReadOnly()) throw new IllegalArgumentException();
T txn = unbox(transaction);
if (!db.containsContact(txn, c))
@@ -903,7 +918,7 @@ class DatabaseComponentImpl<T> implements DatabaseComponent {
@Override
public void setMessageState(Transaction transaction, MessageId m,
State state) throws DbException {
MessageState state) throws DbException {
if (transaction.isReadOnly()) throw new IllegalArgumentException();
T txn = unbox(transaction);
if (!db.containsMessage(txn, m))
@@ -920,10 +935,10 @@ class DatabaseComponentImpl<T> implements DatabaseComponent {
T txn = unbox(transaction);
if (!db.containsMessage(txn, dependent.getId()))
throw new NoSuchMessageException();
State dependentState = db.getMessageState(txn, dependent.getId());
MessageState dependentState =
db.getMessageState(txn, dependent.getId());
for (MessageId dependency : dependencies) {
db.addMessageDependency(txn, dependent, dependency,
dependentState);
db.addMessageDependency(txn, dependent, dependency, dependentState);
}
}
@@ -15,16 +15,23 @@ import java.sql.DriverManager;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Properties;
import java.util.logging.Logger;
import javax.annotation.Nullable;
import javax.inject.Inject;
import static java.util.logging.Level.WARNING;
import static java.util.logging.Logger.getLogger;
import static org.briarproject.bramble.db.JdbcUtils.tryToClose;
/**
* Contains all the H2-specific code for the database.
*/
@NotNullByDefault
class H2Database extends JdbcDatabase {
private static final Logger LOG = getLogger(H2Database.class.getName());
private static final String HASH_TYPE = "BINARY(32)";
private static final String SECRET_TYPE = "BINARY(32)";
private static final String BINARY_TYPE = "BINARY";
@@ -121,8 +128,8 @@ class H2Database extends JdbcDatabase {
s.close();
c.close();
} catch (SQLException e) {
tryToClose(s);
tryToClose(c);
tryToClose(s, LOG, WARNING);
tryToClose(c, LOG, WARNING);
throw new DbException(e);
}
}
@@ -14,16 +14,24 @@ import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.logging.Logger;
import javax.annotation.Nullable;
import javax.inject.Inject;
import static java.util.logging.Level.WARNING;
import static java.util.logging.Logger.getLogger;
import static org.briarproject.bramble.db.JdbcUtils.tryToClose;
/**
* Contains all the HSQLDB-specific code for the database.
*/
@NotNullByDefault
class HyperSqlDatabase extends JdbcDatabase {
private static final Logger LOG =
getLogger(HyperSqlDatabase.class.getName());
private static final String HASH_TYPE = "BINARY(32)";
private static final String SECRET_TYPE = "BINARY(32)";
private static final String BINARY_TYPE = "BINARY";
@@ -72,8 +80,8 @@ class HyperSqlDatabase extends JdbcDatabase {
s.close();
c.close();
} catch (SQLException e) {
tryToClose(s);
tryToClose(c);
tryToClose(s, LOG, WARNING);
tryToClose(c, LOG, WARNING);
throw new DbException(e);
}
}
@@ -122,8 +130,8 @@ class HyperSqlDatabase extends JdbcDatabase {
s.close();
c.close();
} catch (SQLException e) {
tryToClose(s);
tryToClose(c);
tryToClose(s, LOG, WARNING);
tryToClose(c, LOG, WARNING);
throw new DbException(e);
}
}
@@ -24,7 +24,7 @@ import org.briarproject.bramble.api.sync.Message;
import org.briarproject.bramble.api.sync.MessageFactory;
import org.briarproject.bramble.api.sync.MessageId;
import org.briarproject.bramble.api.sync.MessageStatus;
import org.briarproject.bramble.api.sync.ValidationManager.State;
import org.briarproject.bramble.api.sync.validation.MessageState;
import org.briarproject.bramble.api.system.Clock;
import org.briarproject.bramble.api.transport.IncomingKeys;
import org.briarproject.bramble.api.transport.KeySet;
@@ -64,14 +64,15 @@ import static org.briarproject.bramble.api.sync.Group.Visibility.INVISIBLE;
import static org.briarproject.bramble.api.sync.Group.Visibility.SHARED;
import static org.briarproject.bramble.api.sync.Group.Visibility.VISIBLE;
import static org.briarproject.bramble.api.sync.SyncConstants.MESSAGE_HEADER_LENGTH;
import static org.briarproject.bramble.api.sync.ValidationManager.State.DELIVERED;
import static org.briarproject.bramble.api.sync.ValidationManager.State.PENDING;
import static org.briarproject.bramble.api.sync.ValidationManager.State.UNKNOWN;
import static org.briarproject.bramble.api.sync.validation.MessageState.DELIVERED;
import static org.briarproject.bramble.api.sync.validation.MessageState.PENDING;
import static org.briarproject.bramble.api.sync.validation.MessageState.UNKNOWN;
import static org.briarproject.bramble.db.DatabaseConstants.DB_SETTINGS_NAMESPACE;
import static org.briarproject.bramble.db.DatabaseConstants.LAST_COMPACTED_KEY;
import static org.briarproject.bramble.db.DatabaseConstants.MAX_COMPACTION_INTERVAL_MS;
import static org.briarproject.bramble.db.DatabaseConstants.SCHEMA_VERSION_KEY;
import static org.briarproject.bramble.db.ExponentialBackoff.calculateExpiry;
import static org.briarproject.bramble.db.JdbcUtils.tryToClose;
import static org.briarproject.bramble.util.LogUtils.logDuration;
import static org.briarproject.bramble.util.LogUtils.logException;
import static org.briarproject.bramble.util.LogUtils.now;
@@ -458,30 +459,6 @@ abstract class JdbcDatabase implements Database<Connection> {
mergeSettings(txn, s, DB_SETTINGS_NAMESPACE);
}
private void tryToClose(@Nullable ResultSet rs) {
try {
if (rs != null) rs.close();
} catch (SQLException e) {
logException(LOG, WARNING, e);
}
}
protected void tryToClose(@Nullable Statement s) {
try {
if (s != null) s.close();
} catch (SQLException e) {
logException(LOG, WARNING, e);
}
}
protected void tryToClose(@Nullable Connection c) {
try {
if (c != null) c.close();
} catch (SQLException e) {
logException(LOG, WARNING, e);
}
}
private void createTables(Connection txn) throws DbException {
Statement s = null;
try {
@@ -502,7 +479,7 @@ abstract class JdbcDatabase implements Database<Connection> {
s.executeUpdate(dbTypes.replaceTypes(CREATE_INCOMING_KEYS));
s.close();
} catch (SQLException e) {
tryToClose(s);
tryToClose(s, LOG, WARNING);
throw new DbException(e);
}
}
@@ -519,7 +496,7 @@ abstract class JdbcDatabase implements Database<Connection> {
s.executeUpdate(INDEX_STATUSES_BY_CONTACT_ID_TIMESTAMP);
s.close();
} catch (SQLException e) {
tryToClose(s);
tryToClose(s, LOG, WARNING);
throw new DbException(e);
}
}
@@ -566,11 +543,7 @@ abstract class JdbcDatabase implements Database<Connection> {
} catch (SQLException e) {
// Try to close the connection
logException(LOG, WARNING, e);
try {
txn.close();
} catch (SQLException e1) {
logException(LOG, WARNING, e1);
}
tryToClose(txn, LOG, WARNING);
// Whatever happens, allow the database to close
connectionsLock.lock();
try {
@@ -659,8 +632,8 @@ abstract class JdbcDatabase implements Database<Connection> {
ps.close();
return c;
} catch (SQLException e) {
tryToClose(rs);
tryToClose(ps);
tryToClose(rs, LOG, WARNING);
tryToClose(ps, LOG, WARNING);
throw new DbException(e);
}
}
@@ -681,7 +654,7 @@ abstract class JdbcDatabase implements Database<Connection> {
if (affected != 1) throw new DbStateException();
ps.close();
} catch (SQLException e) {
tryToClose(ps);
tryToClose(ps, LOG, WARNING);
throw new DbException(e);
}
}
@@ -704,7 +677,7 @@ abstract class JdbcDatabase implements Database<Connection> {
// Create a status row for each message in the group
addStatus(txn, c, g, groupShared);
} catch (SQLException e) {
tryToClose(ps);
tryToClose(ps, LOG, WARNING);
throw new DbException(e);
}
}
@@ -724,7 +697,7 @@ abstract class JdbcDatabase implements Database<Connection> {
while (rs.next()) {
MessageId id = new MessageId(rs.getBytes(1));
long timestamp = rs.getLong(2);
State state = State.fromValue(rs.getInt(3));
MessageState state = MessageState.fromValue(rs.getInt(3));
boolean messageShared = rs.getBoolean(4);
int length = rs.getInt(5);
boolean deleted = rs.getBoolean(6);
@@ -735,8 +708,8 @@ abstract class JdbcDatabase implements Database<Connection> {
rs.close();
ps.close();
} catch (SQLException e) {
tryToClose(rs);
tryToClose(ps);
tryToClose(rs, LOG, WARNING);
tryToClose(ps, LOG, WARNING);
throw new DbException(e);
}
}
@@ -761,13 +734,13 @@ abstract class JdbcDatabase implements Database<Connection> {
if (affected != 1) throw new DbStateException();
ps.close();
} catch (SQLException e) {
tryToClose(ps);
tryToClose(ps, LOG, WARNING);
throw new DbException(e);
}
}
@Override
public void addMessage(Connection txn, Message m, State state,
public void addMessage(Connection txn, Message m, MessageState state,
boolean messageShared, @Nullable ContactId sender)
throws DbException {
PreparedStatement ps = null;
@@ -810,7 +783,7 @@ abstract class JdbcDatabase implements Database<Connection> {
if (affected < 0) throw new DbStateException();
ps.close();
} catch (SQLException e) {
tryToClose(ps);
tryToClose(ps, LOG, WARNING);
throw new DbException(e);
}
}
@@ -840,14 +813,14 @@ abstract class JdbcDatabase implements Database<Connection> {
if (affected != 1) throw new DbStateException();
ps.close();
} catch (SQLException e) {
tryToClose(rs);
tryToClose(ps);
tryToClose(rs, LOG, WARNING);
tryToClose(ps, LOG, WARNING);
throw new DbException(e);
}
}
private void addStatus(Connection txn, MessageId m, ContactId c, GroupId g,
long timestamp, int length, State state, boolean groupShared,
long timestamp, int length, MessageState state, boolean groupShared,
boolean messageShared, boolean deleted, boolean seen)
throws DbException {
PreparedStatement ps = null;
@@ -873,14 +846,15 @@ abstract class JdbcDatabase implements Database<Connection> {
if (affected != 1) throw new DbStateException();
ps.close();
} catch (SQLException e) {
tryToClose(ps);
tryToClose(ps, LOG, WARNING);
throw new DbException(e);
}
}
@Override
public void addMessageDependency(Connection txn, Message dependent,
MessageId dependency, State dependentState) throws DbException {
MessageId dependency, MessageState dependentState)
throws DbException {
PreparedStatement ps = null;
ResultSet rs = null;
try {
@@ -891,9 +865,9 @@ abstract class JdbcDatabase implements Database<Connection> {
ps.setBytes(1, dependency.getBytes());
ps.setBytes(2, dependent.getGroupId().getBytes());
rs = ps.executeQuery();
State dependencyState = null;
MessageState dependencyState = null;
if (rs.next()) {
dependencyState = State.fromValue(rs.getInt(1));
dependencyState = MessageState.fromValue(rs.getInt(1));
if (rs.next()) throw new DbStateException();
}
rs.close();
@@ -914,8 +888,8 @@ abstract class JdbcDatabase implements Database<Connection> {
if (affected != 1) throw new DbStateException();
ps.close();
} catch (SQLException e) {
tryToClose(rs);
tryToClose(ps);
tryToClose(rs, LOG, WARNING);
tryToClose(ps, LOG, WARNING);
throw new DbException(e);
}
}
@@ -934,7 +908,7 @@ abstract class JdbcDatabase implements Database<Connection> {
if (affected != 1) throw new DbStateException();
ps.close();
} catch (SQLException e) {
tryToClose(ps);
tryToClose(ps, LOG, WARNING);
throw new DbException(e);
}
}
@@ -1014,8 +988,8 @@ abstract class JdbcDatabase implements Database<Connection> {
ps.close();
return keySetId;
} catch (SQLException e) {
tryToClose(rs);
tryToClose(ps);
tryToClose(rs, LOG, WARNING);
tryToClose(ps, LOG, WARNING);
throw new DbException(e);
}
}
@@ -1038,8 +1012,8 @@ abstract class JdbcDatabase implements Database<Connection> {
ps.close();
return found;
} catch (SQLException e) {
tryToClose(rs);
tryToClose(ps);
tryToClose(rs, LOG, WARNING);
tryToClose(ps, LOG, WARNING);
throw new DbException(e);
}
}
@@ -1060,8 +1034,8 @@ abstract class JdbcDatabase implements Database<Connection> {
ps.close();
return found;
} catch (SQLException e) {
tryToClose(rs);
tryToClose(ps);
tryToClose(rs, LOG, WARNING);
tryToClose(ps, LOG, WARNING);
throw new DbException(e);
}
}
@@ -1082,8 +1056,8 @@ abstract class JdbcDatabase implements Database<Connection> {
ps.close();
return found;
} catch (SQLException e) {
tryToClose(rs);
tryToClose(ps);
tryToClose(rs, LOG, WARNING);
tryToClose(ps, LOG, WARNING);
throw new DbException(e);
}
}
@@ -1104,8 +1078,8 @@ abstract class JdbcDatabase implements Database<Connection> {
ps.close();
return found;
} catch (SQLException e) {
tryToClose(rs);
tryToClose(ps);
tryToClose(rs, LOG, WARNING);
tryToClose(ps, LOG, WARNING);
throw new DbException(e);
}
}
@@ -1126,8 +1100,8 @@ abstract class JdbcDatabase implements Database<Connection> {
ps.close();
return found;
} catch (SQLException e) {
tryToClose(rs);
tryToClose(ps);
tryToClose(rs, LOG, WARNING);
tryToClose(ps, LOG, WARNING);
throw new DbException(e);
}
}
@@ -1148,8 +1122,8 @@ abstract class JdbcDatabase implements Database<Connection> {
ps.close();
return found;
} catch (SQLException e) {
tryToClose(rs);
tryToClose(ps);
tryToClose(rs, LOG, WARNING);
tryToClose(ps, LOG, WARNING);
throw new DbException(e);
}
}
@@ -1173,8 +1147,8 @@ abstract class JdbcDatabase implements Database<Connection> {
ps.close();
return found;
} catch (SQLException e) {
tryToClose(rs);
tryToClose(ps);
tryToClose(rs, LOG, WARNING);
tryToClose(ps, LOG, WARNING);
throw new DbException(e);
}
}
@@ -1197,8 +1171,8 @@ abstract class JdbcDatabase implements Database<Connection> {
ps.close();
return count;
} catch (SQLException e) {
tryToClose(rs);
tryToClose(ps);
tryToClose(rs, LOG, WARNING);
tryToClose(ps, LOG, WARNING);
throw new DbException(e);
}
}
@@ -1222,7 +1196,7 @@ abstract class JdbcDatabase implements Database<Connection> {
if (affected < 0) throw new DbStateException();
ps.close();
} catch (SQLException e) {
tryToClose(ps);
tryToClose(ps, LOG, WARNING);
throw new DbException(e);
}
}
@@ -1239,7 +1213,7 @@ abstract class JdbcDatabase implements Database<Connection> {
if (affected < 0) throw new DbStateException();
ps.close();
} catch (SQLException e) {
tryToClose(ps);
tryToClose(ps, LOG, WARNING);
throw new DbException(e);
}
}
@@ -1272,8 +1246,8 @@ abstract class JdbcDatabase implements Database<Connection> {
return new Contact(c, author, localAuthorId, alias, verified,
active);
} catch (SQLException e) {
tryToClose(rs);
tryToClose(ps);
tryToClose(rs, LOG, WARNING);
tryToClose(ps, LOG, WARNING);
throw new DbException(e);
}
}
@@ -1309,8 +1283,8 @@ abstract class JdbcDatabase implements Database<Connection> {
ps.close();
return contacts;
} catch (SQLException e) {
tryToClose(rs);
tryToClose(ps);
tryToClose(rs, LOG, WARNING);
tryToClose(ps, LOG, WARNING);
throw new DbException(e);
}
}
@@ -1332,8 +1306,8 @@ abstract class JdbcDatabase implements Database<Connection> {
ps.close();
return ids;
} catch (SQLException e) {
tryToClose(rs);
tryToClose(ps);
tryToClose(rs, LOG, WARNING);
tryToClose(ps, LOG, WARNING);
throw new DbException(e);
}
}
@@ -1370,8 +1344,8 @@ abstract class JdbcDatabase implements Database<Connection> {
ps.close();
return contacts;
} catch (SQLException e) {
tryToClose(rs);
tryToClose(ps);
tryToClose(rs, LOG, WARNING);
tryToClose(ps, LOG, WARNING);
throw new DbException(e);
}
}
@@ -1394,8 +1368,8 @@ abstract class JdbcDatabase implements Database<Connection> {
ps.close();
return new Group(g, clientId, majorVersion, descriptor);
} catch (SQLException e) {
tryToClose(rs);
tryToClose(ps);
tryToClose(rs, LOG, WARNING);
tryToClose(ps, LOG, WARNING);
throw new DbException(e);
}
}
@@ -1422,8 +1396,8 @@ abstract class JdbcDatabase implements Database<Connection> {
ps.close();
return groups;
} catch (SQLException e) {
tryToClose(rs);
tryToClose(ps);
tryToClose(rs, LOG, WARNING);
tryToClose(ps, LOG, WARNING);
throw new DbException(e);
}
}
@@ -1448,8 +1422,8 @@ abstract class JdbcDatabase implements Database<Connection> {
ps.close();
return v;
} catch (SQLException e) {
tryToClose(rs);
tryToClose(ps);
tryToClose(rs, LOG, WARNING);
tryToClose(ps, LOG, WARNING);
throw new DbException(e);
}
}
@@ -1472,8 +1446,8 @@ abstract class JdbcDatabase implements Database<Connection> {
ps.close();
return visible;
} catch (SQLException e) {
tryToClose(rs);
tryToClose(ps);
tryToClose(rs, LOG, WARNING);
tryToClose(ps, LOG, WARNING);
throw new DbException(e);
}
}
@@ -1504,8 +1478,8 @@ abstract class JdbcDatabase implements Database<Connection> {
ps.close();
return localAuthor;
} catch (SQLException e) {
tryToClose(rs);
tryToClose(ps);
tryToClose(rs, LOG, WARNING);
tryToClose(ps, LOG, WARNING);
throw new DbException(e);
}
}
@@ -1536,8 +1510,8 @@ abstract class JdbcDatabase implements Database<Connection> {
ps.close();
return authors;
} catch (SQLException e) {
tryToClose(rs);
tryToClose(ps);
tryToClose(rs, LOG, WARNING);
tryToClose(ps, LOG, WARNING);
throw new DbException(e);
}
}
@@ -1565,8 +1539,8 @@ abstract class JdbcDatabase implements Database<Connection> {
System.arraycopy(raw, MESSAGE_HEADER_LENGTH, body, 0, body.length);
return new Message(m, g, timestamp, body);
} catch (SQLException e) {
tryToClose(rs);
tryToClose(ps);
tryToClose(rs, LOG, WARNING);
tryToClose(ps, LOG, WARNING);
throw new DbException(e);
}
}
@@ -1589,8 +1563,8 @@ abstract class JdbcDatabase implements Database<Connection> {
ps.close();
return ids;
} catch (SQLException e) {
tryToClose(rs);
tryToClose(ps);
tryToClose(rs, LOG, WARNING);
tryToClose(ps, LOG, WARNING);
throw new DbException(e);
}
}
@@ -1627,8 +1601,8 @@ abstract class JdbcDatabase implements Database<Connection> {
if (intersection == null) throw new AssertionError();
return intersection;
} catch (SQLException e) {
tryToClose(rs);
tryToClose(ps);
tryToClose(rs, LOG, WARNING);
tryToClose(ps, LOG, WARNING);
throw new DbException(e);
}
}
@@ -1660,8 +1634,8 @@ abstract class JdbcDatabase implements Database<Connection> {
ps.close();
return all;
} catch (SQLException e) {
tryToClose(rs);
tryToClose(ps);
tryToClose(rs, LOG, WARNING);
tryToClose(ps, LOG, WARNING);
throw new DbException(e);
}
}
@@ -1695,8 +1669,8 @@ abstract class JdbcDatabase implements Database<Connection> {
ps.close();
return metadata;
} catch (SQLException e) {
tryToClose(rs);
tryToClose(ps);
tryToClose(rs, LOG, WARNING);
tryToClose(ps, LOG, WARNING);
throw new DbException(e);
}
}
@@ -1719,8 +1693,8 @@ abstract class JdbcDatabase implements Database<Connection> {
ps.close();
return metadata;
} catch (SQLException e) {
tryToClose(rs);
tryToClose(ps);
tryToClose(rs, LOG, WARNING);
tryToClose(ps, LOG, WARNING);
throw new DbException(e);
}
}
@@ -1745,8 +1719,8 @@ abstract class JdbcDatabase implements Database<Connection> {
ps.close();
return metadata;
} catch (SQLException e) {
tryToClose(rs);
tryToClose(ps);
tryToClose(rs, LOG, WARNING);
tryToClose(ps, LOG, WARNING);
throw new DbException(e);
}
}
@@ -1775,8 +1749,8 @@ abstract class JdbcDatabase implements Database<Connection> {
ps.close();
return statuses;
} catch (SQLException e) {
tryToClose(rs);
tryToClose(ps);
tryToClose(rs, LOG, WARNING);
tryToClose(ps, LOG, WARNING);
throw new DbException(e);
}
}
@@ -1806,14 +1780,14 @@ abstract class JdbcDatabase implements Database<Connection> {
ps.close();
return status;
} catch (SQLException e) {
tryToClose(rs);
tryToClose(ps);
tryToClose(rs, LOG, WARNING);
tryToClose(ps, LOG, WARNING);
throw new DbException(e);
}
}
@Override
public Map<MessageId, State> getMessageDependencies(Connection txn,
public Map<MessageId, MessageState> getMessageDependencies(Connection txn,
MessageId m) throws DbException {
PreparedStatement ps = null;
ResultSet rs = null;
@@ -1824,10 +1798,10 @@ abstract class JdbcDatabase implements Database<Connection> {
ps = txn.prepareStatement(sql);
ps.setBytes(1, m.getBytes());
rs = ps.executeQuery();
Map<MessageId, State> dependencies = new HashMap<>();
Map<MessageId, MessageState> dependencies = new HashMap<>();
while (rs.next()) {
MessageId dependency = new MessageId(rs.getBytes(1));
State state = State.fromValue(rs.getInt(2));
MessageState state = MessageState.fromValue(rs.getInt(2));
if (rs.wasNull())
state = UNKNOWN; // Missing or in a different group
dependencies.put(dependency, state);
@@ -1836,14 +1810,14 @@ abstract class JdbcDatabase implements Database<Connection> {
ps.close();
return dependencies;
} catch (SQLException e) {
tryToClose(rs);
tryToClose(ps);
tryToClose(rs, LOG, WARNING);
tryToClose(ps, LOG, WARNING);
throw new DbException(e);
}
}
@Override
public Map<MessageId, State> getMessageDependents(Connection txn,
public Map<MessageId, MessageState> getMessageDependents(Connection txn,
MessageId m) throws DbException {
PreparedStatement ps = null;
ResultSet rs = null;
@@ -1857,24 +1831,24 @@ abstract class JdbcDatabase implements Database<Connection> {
ps = txn.prepareStatement(sql);
ps.setBytes(1, m.getBytes());
rs = ps.executeQuery();
Map<MessageId, State> dependents = new HashMap<>();
Map<MessageId, MessageState> dependents = new HashMap<>();
while (rs.next()) {
MessageId dependent = new MessageId(rs.getBytes(1));
State state = State.fromValue(rs.getInt(2));
MessageState state = MessageState.fromValue(rs.getInt(2));
dependents.put(dependent, state);
}
rs.close();
ps.close();
return dependents;
} catch (SQLException e) {
tryToClose(rs);
tryToClose(ps);
tryToClose(rs, LOG, WARNING);
tryToClose(ps, LOG, WARNING);
throw new DbException(e);
}
}
@Override
public State getMessageState(Connection txn, MessageId m)
public MessageState getMessageState(Connection txn, MessageId m)
throws DbException {
PreparedStatement ps = null;
ResultSet rs = null;
@@ -1884,14 +1858,14 @@ abstract class JdbcDatabase implements Database<Connection> {
ps.setBytes(1, m.getBytes());
rs = ps.executeQuery();
if (!rs.next()) throw new DbStateException();
State state = State.fromValue(rs.getInt(1));
MessageState state = MessageState.fromValue(rs.getInt(1));
if (rs.next()) throw new DbStateException();
rs.close();
ps.close();
return state;
} catch (SQLException e) {
tryToClose(rs);
tryToClose(ps);
tryToClose(rs, LOG, WARNING);
tryToClose(ps, LOG, WARNING);
throw new DbException(e);
}
}
@@ -1915,8 +1889,8 @@ abstract class JdbcDatabase implements Database<Connection> {
ps.close();
return ids;
} catch (SQLException e) {
tryToClose(rs);
tryToClose(ps);
tryToClose(rs, LOG, WARNING);
tryToClose(ps, LOG, WARNING);
throw new DbException(e);
}
}
@@ -1949,8 +1923,8 @@ abstract class JdbcDatabase implements Database<Connection> {
ps.close();
return ids;
} catch (SQLException e) {
tryToClose(rs);
tryToClose(ps);
tryToClose(rs, LOG, WARNING);
tryToClose(ps, LOG, WARNING);
throw new DbException(e);
}
}
@@ -1974,8 +1948,8 @@ abstract class JdbcDatabase implements Database<Connection> {
ps.close();
return ids;
} catch (SQLException e) {
tryToClose(rs);
tryToClose(ps);
tryToClose(rs, LOG, WARNING);
tryToClose(ps, LOG, WARNING);
throw new DbException(e);
}
}
@@ -2013,8 +1987,8 @@ abstract class JdbcDatabase implements Database<Connection> {
ps.close();
return ids;
} catch (SQLException e) {
tryToClose(rs);
tryToClose(ps);
tryToClose(rs, LOG, WARNING);
tryToClose(ps, LOG, WARNING);
throw new DbException(e);
}
}
@@ -2032,7 +2006,7 @@ abstract class JdbcDatabase implements Database<Connection> {
}
private Collection<MessageId> getMessagesInState(Connection txn,
State state) throws DbException {
MessageState state) throws DbException {
PreparedStatement ps = null;
ResultSet rs = null;
try {
@@ -2047,8 +2021,8 @@ abstract class JdbcDatabase implements Database<Connection> {
ps.close();
return ids;
} catch (SQLException e) {
tryToClose(rs);
tryToClose(ps);
tryToClose(rs, LOG, WARNING);
tryToClose(ps, LOG, WARNING);
throw new DbException(e);
}
}
@@ -2075,8 +2049,8 @@ abstract class JdbcDatabase implements Database<Connection> {
ps.close();
return ids;
} catch (SQLException e) {
tryToClose(rs);
tryToClose(ps);
tryToClose(rs, LOG, WARNING);
tryToClose(ps, LOG, WARNING);
throw new DbException(e);
}
}
@@ -2105,8 +2079,8 @@ abstract class JdbcDatabase implements Database<Connection> {
ps.close();
return nextSendTime;
} catch (SQLException e) {
tryToClose(rs);
tryToClose(ps);
tryToClose(rs, LOG, WARNING);
tryToClose(ps, LOG, WARNING);
throw new DbException(e);
}
}
@@ -2144,8 +2118,8 @@ abstract class JdbcDatabase implements Database<Connection> {
ps.close();
return ids;
} catch (SQLException e) {
tryToClose(rs);
tryToClose(ps);
tryToClose(rs, LOG, WARNING);
tryToClose(ps, LOG, WARNING);
throw new DbException(e);
}
}
@@ -2167,8 +2141,8 @@ abstract class JdbcDatabase implements Database<Connection> {
ps.close();
return s;
} catch (SQLException e) {
tryToClose(rs);
tryToClose(ps);
tryToClose(rs, LOG, WARNING);
tryToClose(ps, LOG, WARNING);
throw new DbException(e);
}
}
@@ -2233,8 +2207,8 @@ abstract class JdbcDatabase implements Database<Connection> {
ps.close();
return keys;
} catch (SQLException e) {
tryToClose(rs);
tryToClose(ps);
tryToClose(rs, LOG, WARNING);
tryToClose(ps, LOG, WARNING);
throw new DbException(e);
}
}
@@ -2253,7 +2227,7 @@ abstract class JdbcDatabase implements Database<Connection> {
if (affected != 1) throw new DbStateException();
ps.close();
} catch (SQLException e) {
tryToClose(ps);
tryToClose(ps, LOG, WARNING);
throw new DbException(e);
}
}
@@ -2280,7 +2254,7 @@ abstract class JdbcDatabase implements Database<Connection> {
}
ps.close();
} catch (SQLException e) {
tryToClose(ps);
tryToClose(ps, LOG, WARNING);
throw new DbException(e);
}
}
@@ -2307,7 +2281,7 @@ abstract class JdbcDatabase implements Database<Connection> {
}
ps.close();
} catch (SQLException e) {
tryToClose(ps);
tryToClose(ps, LOG, WARNING);
throw new DbException(e);
}
}
@@ -2337,7 +2311,7 @@ abstract class JdbcDatabase implements Database<Connection> {
if (rows != 1) throw new DbStateException();
ps.close();
} catch (SQLException e) {
tryToClose(ps);
tryToClose(ps, LOG, WARNING);
throw new DbException(e);
}
}
@@ -2359,7 +2333,7 @@ abstract class JdbcDatabase implements Database<Connection> {
rs = ps.executeQuery();
if (!rs.next()) throw new DbStateException();
GroupId g = new GroupId(rs.getBytes(1));
State state = State.fromValue(rs.getInt(2));
MessageState state = MessageState.fromValue(rs.getInt(2));
rs.close();
ps.close();
// Insert any keys that don't already exist
@@ -2382,8 +2356,8 @@ abstract class JdbcDatabase implements Database<Connection> {
if (rows != 1) throw new DbStateException();
ps.close();
} catch (SQLException e) {
tryToClose(rs);
tryToClose(ps);
tryToClose(rs, LOG, WARNING);
tryToClose(ps, LOG, WARNING);
throw new DbException(e);
}
}
@@ -2449,7 +2423,7 @@ abstract class JdbcDatabase implements Database<Connection> {
}
return added;
} catch (SQLException e) {
tryToClose(ps);
tryToClose(ps, LOG, WARNING);
throw new DbException(e);
}
}
@@ -2496,7 +2470,7 @@ abstract class JdbcDatabase implements Database<Connection> {
if (rows != 1) throw new DbStateException();
ps.close();
} catch (SQLException e) {
tryToClose(ps);
tryToClose(ps, LOG, WARNING);
throw new DbException(e);
}
}
@@ -2515,7 +2489,7 @@ abstract class JdbcDatabase implements Database<Connection> {
if (affected < 0 || affected > 1) throw new DbStateException();
ps.close();
} catch (SQLException e) {
tryToClose(ps);
tryToClose(ps, LOG, WARNING);
throw new DbException(e);
}
}
@@ -2534,7 +2508,7 @@ abstract class JdbcDatabase implements Database<Connection> {
if (affected < 0 || affected > 1) throw new DbStateException();
ps.close();
} catch (SQLException e) {
tryToClose(ps);
tryToClose(ps, LOG, WARNING);
throw new DbException(e);
}
}
@@ -2553,7 +2527,7 @@ abstract class JdbcDatabase implements Database<Connection> {
if (affected < 0 || affected > 1) throw new DbStateException();
ps.close();
} catch (SQLException e) {
tryToClose(ps);
tryToClose(ps, LOG, WARNING);
throw new DbException(e);
}
}
@@ -2570,7 +2544,7 @@ abstract class JdbcDatabase implements Database<Connection> {
if (affected != 1) throw new DbStateException();
ps.close();
} catch (SQLException e) {
tryToClose(ps);
tryToClose(ps, LOG, WARNING);
throw new DbException(e);
}
}
@@ -2586,7 +2560,7 @@ abstract class JdbcDatabase implements Database<Connection> {
if (affected != 1) throw new DbStateException();
ps.close();
} catch (SQLException e) {
tryToClose(ps);
tryToClose(ps, LOG, WARNING);
throw new DbException(e);
}
}
@@ -2614,7 +2588,7 @@ abstract class JdbcDatabase implements Database<Connection> {
if (affected < 0) throw new DbStateException();
ps.close();
} catch (SQLException e) {
tryToClose(ps);
tryToClose(ps, LOG, WARNING);
throw new DbException(e);
}
}
@@ -2631,7 +2605,7 @@ abstract class JdbcDatabase implements Database<Connection> {
if (affected != 1) throw new DbStateException();
ps.close();
} catch (SQLException e) {
tryToClose(ps);
tryToClose(ps, LOG, WARNING);
throw new DbException(e);
}
}
@@ -2647,7 +2621,7 @@ abstract class JdbcDatabase implements Database<Connection> {
if (affected != 1) throw new DbStateException();
ps.close();
} catch (SQLException e) {
tryToClose(ps);
tryToClose(ps, LOG, WARNING);
throw new DbException(e);
}
}
@@ -2666,7 +2640,7 @@ abstract class JdbcDatabase implements Database<Connection> {
ps.close();
return affected == 1;
} catch (SQLException e) {
tryToClose(ps);
tryToClose(ps, LOG, WARNING);
throw new DbException(e);
}
}
@@ -2691,7 +2665,7 @@ abstract class JdbcDatabase implements Database<Connection> {
if (rows != 1) throw new DbStateException();
ps.close();
} catch (SQLException e) {
tryToClose(ps);
tryToClose(ps, LOG, WARNING);
throw new DbException(e);
}
}
@@ -2708,7 +2682,7 @@ abstract class JdbcDatabase implements Database<Connection> {
if (affected != 1) throw new DbStateException();
ps.close();
} catch (SQLException e) {
tryToClose(ps);
tryToClose(ps, LOG, WARNING);
throw new DbException(e);
}
}
@@ -2729,7 +2703,7 @@ abstract class JdbcDatabase implements Database<Connection> {
if (affected < 0) throw new DbStateException();
ps.close();
} catch (SQLException e) {
tryToClose(ps);
tryToClose(ps, LOG, WARNING);
throw new DbException(e);
}
}
@@ -2748,7 +2722,7 @@ abstract class JdbcDatabase implements Database<Connection> {
if (affected < 0 || affected > 1) throw new DbStateException();
ps.close();
} catch (SQLException e) {
tryToClose(ps);
tryToClose(ps, LOG, WARNING);
throw new DbException(e);
}
}
@@ -2766,7 +2740,7 @@ abstract class JdbcDatabase implements Database<Connection> {
if (affected < 0 || affected > 1) throw new DbStateException();
ps.close();
} catch (SQLException e) {
tryToClose(ps);
tryToClose(ps, LOG, WARNING);
throw new DbException(e);
}
}
@@ -2784,7 +2758,7 @@ abstract class JdbcDatabase implements Database<Connection> {
if (affected < 0 || affected > 1) throw new DbStateException();
ps.close();
} catch (SQLException e) {
tryToClose(ps);
tryToClose(ps, LOG, WARNING);
throw new DbException(e);
}
}
@@ -2803,7 +2777,7 @@ abstract class JdbcDatabase implements Database<Connection> {
if (affected < 0 || affected > 1) throw new DbStateException();
ps.close();
} catch (SQLException e) {
tryToClose(ps);
tryToClose(ps, LOG, WARNING);
throw new DbException(e);
}
}
@@ -2833,7 +2807,7 @@ abstract class JdbcDatabase implements Database<Connection> {
if (affected < 0) throw new DbStateException();
ps.close();
} catch (SQLException e) {
tryToClose(ps);
tryToClose(ps, LOG, WARNING);
throw new DbException(e);
}
}
@@ -2859,13 +2833,13 @@ abstract class JdbcDatabase implements Database<Connection> {
if (affected < 0) throw new DbStateException();
ps.close();
} catch (SQLException e) {
tryToClose(ps);
tryToClose(ps, LOG, WARNING);
throw new DbException(e);
}
}
@Override
public void setMessageState(Connection txn, MessageId m, State state)
public void setMessageState(Connection txn, MessageId m, MessageState state)
throws DbException {
PreparedStatement ps = null;
try {
@@ -2912,7 +2886,7 @@ abstract class JdbcDatabase implements Database<Connection> {
if (affected < 0) throw new DbStateException();
ps.close();
} catch (SQLException e) {
tryToClose(ps);
tryToClose(ps, LOG, WARNING);
throw new DbException(e);
}
}
@@ -2935,7 +2909,7 @@ abstract class JdbcDatabase implements Database<Connection> {
if (affected < 0 || affected > 1) throw new DbStateException();
ps.close();
} catch (SQLException e) {
tryToClose(ps);
tryToClose(ps, LOG, WARNING);
throw new DbException(e);
}
}
@@ -2954,7 +2928,7 @@ abstract class JdbcDatabase implements Database<Connection> {
if (affected < 0 || affected > 1) throw new DbStateException();
ps.close();
} catch (SQLException e) {
tryToClose(ps);
tryToClose(ps, LOG, WARNING);
throw new DbException(e);
}
}
@@ -2990,8 +2964,8 @@ abstract class JdbcDatabase implements Database<Connection> {
if (affected != 1) throw new DbStateException();
ps.close();
} catch (SQLException e) {
tryToClose(rs);
tryToClose(ps);
tryToClose(rs, LOG, WARNING);
tryToClose(ps, LOG, WARNING);
throw new DbException(e);
}
}
@@ -3058,7 +3032,7 @@ abstract class JdbcDatabase implements Database<Connection> {
if (rows < 0 || rows > 1) throw new DbStateException();
ps.close();
} catch (SQLException e) {
tryToClose(ps);
tryToClose(ps, LOG, WARNING);
throw new DbException(e);
}
}
@@ -0,0 +1,42 @@
package org.briarproject.bramble.db;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.annotation.Nullable;
import static org.briarproject.bramble.util.LogUtils.logException;
@NotNullByDefault
class JdbcUtils {
static void tryToClose(@Nullable ResultSet rs, Logger logger, Level level) {
try {
if (rs != null) rs.close();
} catch (SQLException e) {
logException(logger, level, e);
}
}
static void tryToClose(@Nullable Statement s, Logger logger, Level level) {
try {
if (s != null) s.close();
} catch (SQLException e) {
logException(logger, level, e);
}
}
static void tryToClose(@Nullable Connection c, Logger logger, Level level) {
try {
if (c != null) c.close();
} catch (SQLException e) {
logException(logger, level, e);
}
}
}
@@ -7,10 +7,8 @@ import java.sql.SQLException;
import java.sql.Statement;
import java.util.logging.Logger;
import javax.annotation.Nullable;
import static java.util.logging.Level.WARNING;
import static org.briarproject.bramble.util.LogUtils.logException;
import static org.briarproject.bramble.db.JdbcUtils.tryToClose;
class Migration38_39 implements Migration<Connection> {
@@ -40,16 +38,8 @@ class Migration38_39 implements Migration<Connection> {
+ " ALTER COLUMN contactId"
+ " SET NOT NULL");
} catch (SQLException e) {
tryToClose(s);
tryToClose(s, LOG, WARNING);
throw new DbException(e);
}
}
private void tryToClose(@Nullable Statement s) {
try {
if (s != null) s.close();
} catch (SQLException e) {
logException(LOG, WARNING, e);
}
}
}
@@ -7,10 +7,8 @@ import java.sql.SQLException;
import java.sql.Statement;
import java.util.logging.Logger;
import javax.annotation.Nullable;
import static java.util.logging.Level.WARNING;
import static org.briarproject.bramble.util.LogUtils.logException;
import static org.briarproject.bramble.db.JdbcUtils.tryToClose;
class Migration39_40 implements Migration<Connection> {
@@ -39,16 +37,8 @@ class Migration39_40 implements Migration<Connection> {
+ " ALTER COLUMN eta"
+ " SET NOT NULL");
} catch (SQLException e) {
tryToClose(s);
tryToClose(s, LOG, WARNING);
throw new DbException(e);
}
}
private void tryToClose(@Nullable Statement s) {
try {
if (s != null) s.close();
} catch (SQLException e) {
logException(LOG, WARNING, e);
}
}
}
@@ -7,11 +7,9 @@ import java.sql.SQLException;
import java.sql.Statement;
import java.util.logging.Logger;
import javax.annotation.Nullable;
import static java.util.logging.Level.WARNING;
import static java.util.logging.Logger.getLogger;
import static org.briarproject.bramble.util.LogUtils.logException;
import static org.briarproject.bramble.db.JdbcUtils.tryToClose;
class Migration40_41 implements Migration<Connection> {
@@ -39,18 +37,10 @@ class Migration40_41 implements Migration<Connection> {
try {
s = txn.createStatement();
s.execute("ALTER TABLE contacts"
+ dbTypes.replaceTypes(" ADD alias VARCHAR"));
+ dbTypes.replaceTypes(" ADD alias _STRING"));
} catch (SQLException e) {
tryToClose(s);
tryToClose(s, LOG, WARNING);
throw new DbException(e);
}
}
private void tryToClose(@Nullable Statement s) {
try {
if (s != null) s.close();
} catch (SQLException e) {
logException(LOG, WARNING, e);
}
}
}
@@ -67,27 +67,16 @@ class IdentityManagerImpl implements IdentityManager {
LOG.info("No local author to store");
return;
}
Transaction txn = db.startTransaction(false);
try {
db.addLocalAuthor(txn, cached);
db.commitTransaction(txn);
db.transaction(false, txn -> db.addLocalAuthor(txn, cached));
LOG.info("Local author stored");
} finally {
db.endTransaction(txn);
}
}
@Override
public LocalAuthor getLocalAuthor() throws DbException {
if (cachedAuthor == null) {
Transaction txn = db.startTransaction(true);
try {
cachedAuthor = loadLocalAuthor(txn);
cachedAuthor =
db.transactionWithResult(true, this::loadLocalAuthor);
LOG.info("Local author loaded");
db.commitTransaction(txn);
} finally {
db.endTransaction(txn);
}
}
LocalAuthor cached = cachedAuthor;
if (cached == null) throw new AssertionError();
@@ -6,7 +6,6 @@ import org.briarproject.bramble.api.db.DataTooOldException;
import org.briarproject.bramble.api.db.DatabaseComponent;
import org.briarproject.bramble.api.db.DbException;
import org.briarproject.bramble.api.db.MigrationListener;
import org.briarproject.bramble.api.db.Transaction;
import org.briarproject.bramble.api.event.EventBus;
import org.briarproject.bramble.api.identity.IdentityManager;
import org.briarproject.bramble.api.lifecycle.LifecycleManager;
@@ -115,20 +114,16 @@ class LifecycleManagerImpl implements LifecycleManager, MigrationListener {
dbLatch.countDown();
eventBus.broadcast(new LifecycleEvent(STARTING_SERVICES));
Transaction txn = db.startTransaction(false);
try {
db.transaction(false, txn -> {
for (Client c : clients) {
start = now();
long start1 = now();
c.createLocalState(txn);
if (LOG.isLoggable(FINE)) {
logDuration(LOG, "Starting client "
+ c.getClass().getSimpleName(), start);
+ c.getClass().getSimpleName(), start1);
}
}
db.commitTransaction(txn);
} finally {
db.endTransaction(txn);
}
});
for (Service s : services) {
start = now();
s.startService();
@@ -4,12 +4,11 @@ import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import org.briarproject.bramble.api.plugin.TransportConnectionReader;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.util.logging.Logger;
import static java.util.logging.Level.WARNING;
import static org.briarproject.bramble.util.LogUtils.logException;
import static org.briarproject.bramble.util.IoUtils.tryToClose;
@NotNullByDefault
class FileTransportReader implements TransportConnectionReader {
@@ -34,11 +33,7 @@ class FileTransportReader implements TransportConnectionReader {
@Override
public void dispose(boolean exception, boolean recognised) {
try {
in.close();
} catch (IOException e) {
logException(LOG, WARNING, e);
}
tryToClose(in, LOG, WARNING);
plugin.readerFinished(file, exception, recognised);
}
}
@@ -4,12 +4,11 @@ import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import org.briarproject.bramble.api.plugin.TransportConnectionWriter;
import java.io.File;
import java.io.IOException;
import java.io.OutputStream;
import java.util.logging.Logger;
import static java.util.logging.Level.WARNING;
import static org.briarproject.bramble.util.LogUtils.logException;
import static org.briarproject.bramble.util.IoUtils.tryToClose;
@NotNullByDefault
class FileTransportWriter implements TransportConnectionWriter {
@@ -44,11 +43,7 @@ class FileTransportWriter implements TransportConnectionWriter {
@Override
public void dispose(boolean exception) {
try {
out.close();
} catch (IOException e) {
logException(LOG, WARNING, e);
}
tryToClose(out, LOG, WARNING);
plugin.writerFinished(file, exception);
}
}
@@ -11,6 +11,7 @@ import org.briarproject.bramble.api.plugin.duplex.DuplexPluginCallback;
import org.briarproject.bramble.api.plugin.duplex.DuplexTransportConnection;
import org.briarproject.bramble.api.properties.TransportProperties;
import org.briarproject.bramble.api.settings.Settings;
import org.briarproject.bramble.util.IoUtils;
import org.briarproject.bramble.util.StringUtils;
import java.io.IOException;
@@ -35,7 +36,6 @@ import static org.briarproject.bramble.api.plugin.LanTcpConstants.ID;
import static org.briarproject.bramble.api.plugin.LanTcpConstants.PREF_LAN_IP_PORTS;
import static org.briarproject.bramble.api.plugin.LanTcpConstants.PROP_IP_PORTS;
import static org.briarproject.bramble.util.ByteUtils.MAX_16_BIT_UNSIGNED;
import static org.briarproject.bramble.util.LogUtils.logException;
import static org.briarproject.bramble.util.PrivacyUtils.scrubSocketAddress;
@NotNullByDefault
@@ -293,11 +293,7 @@ class LanTcpPlugin extends TcpPlugin {
@Override
public void close() {
try {
ss.close();
} catch (IOException e) {
logException(LOG, WARNING, e);
}
IoUtils.tryToClose(ss, LOG, WARNING);
}
}
@@ -11,6 +11,7 @@ import org.briarproject.bramble.api.plugin.duplex.DuplexPlugin;
import org.briarproject.bramble.api.plugin.duplex.DuplexPluginCallback;
import org.briarproject.bramble.api.plugin.duplex.DuplexTransportConnection;
import org.briarproject.bramble.api.properties.TransportProperties;
import org.briarproject.bramble.util.IoUtils;
import org.briarproject.bramble.util.StringUtils;
import java.io.IOException;
@@ -153,14 +154,9 @@ abstract class TcpPlugin implements DuplexPlugin {
}
protected void tryToClose(@Nullable ServerSocket ss) {
try {
if (ss != null) ss.close();
} catch (IOException e) {
logException(LOG, WARNING, e);
} finally {
IoUtils.tryToClose(ss, LOG, WARNING);
callback.transportDisabled();
}
}
String getIpPortString(InetSocketAddress a) {
String addr = a.getAddress().getHostAddress();
@@ -4,6 +4,8 @@ import net.freehaven.tor.control.EventHandler;
import net.freehaven.tor.control.TorControlConnection;
import org.briarproject.bramble.PoliteExecutor;
import org.briarproject.bramble.api.battery.BatteryManager;
import org.briarproject.bramble.api.battery.event.BatteryEvent;
import org.briarproject.bramble.api.contact.ContactId;
import org.briarproject.bramble.api.data.BdfList;
import org.briarproject.bramble.api.event.Event;
@@ -29,7 +31,6 @@ import org.briarproject.bramble.api.system.LocationUtils;
import org.briarproject.bramble.api.system.ResourceProvider;
import org.briarproject.bramble.util.IoUtils;
import java.io.Closeable;
import java.io.EOFException;
import java.io.File;
import java.io.FileInputStream;
@@ -96,13 +97,14 @@ abstract class TorPlugin implements DuplexPlugin, EventHandler, EventListener {
private final LocationUtils locationUtils;
private final SocketFactory torSocketFactory;
private final Clock clock;
private final BatteryManager batteryManager;
private final Backoff backoff;
private final DuplexPluginCallback callback;
private final String architecture;
private final CircumventionProvider circumventionProvider;
private final ResourceProvider resourceProvider;
private final int maxLatency, maxIdleTime, socketTimeout;
private final File torDirectory, torFile, geoIpFile, configFile;
private final File torDirectory, torFile, geoIpFile, obfs4File, configFile;
private final File doneFile, cookieFile;
private final ConnectionStatus connectionStatus;
private final AtomicBoolean used = new AtomicBoolean(false);
@@ -121,7 +123,8 @@ abstract class TorPlugin implements DuplexPlugin, EventHandler, EventListener {
TorPlugin(Executor ioExecutor, NetworkManager networkManager,
LocationUtils locationUtils, SocketFactory torSocketFactory,
Clock clock, ResourceProvider resourceProvider,
CircumventionProvider circumventionProvider, Backoff backoff,
CircumventionProvider circumventionProvider,
BatteryManager batteryManager, Backoff backoff,
DuplexPluginCallback callback, String architecture, int maxLatency,
int maxIdleTime, File torDirectory) {
this.ioExecutor = ioExecutor;
@@ -131,6 +134,7 @@ abstract class TorPlugin implements DuplexPlugin, EventHandler, EventListener {
this.clock = clock;
this.resourceProvider = resourceProvider;
this.circumventionProvider = circumventionProvider;
this.batteryManager = batteryManager;
this.backoff = backoff;
this.callback = callback;
this.architecture = architecture;
@@ -142,6 +146,7 @@ abstract class TorPlugin implements DuplexPlugin, EventHandler, EventListener {
this.torDirectory = torDirectory;
torFile = new File(torDirectory, "tor");
geoIpFile = new File(torDirectory, "geoip");
obfs4File = new File(torDirectory, "obfs4proxy");
configFile = new File(torDirectory, "torrc");
doneFile = new File(torDirectory, "done");
cookieFile = new File(torDirectory, ".tor/control_auth_cookie");
@@ -260,7 +265,8 @@ abstract class TorPlugin implements DuplexPlugin, EventHandler, EventListener {
throw new PluginException(e);
}
// Check whether we're online
updateConnectionStatus(networkManager.getNetworkStatus());
updateConnectionStatus(networkManager.getNetworkStatus(),
batteryManager.isCharging());
// Bind a server socket to receive incoming hidden service connections
bind();
}
@@ -284,14 +290,20 @@ abstract class TorPlugin implements DuplexPlugin, EventHandler, EventListener {
in = getGeoIpInputStream();
out = new FileOutputStream(geoIpFile);
IoUtils.copyAndClose(in, out);
// Unzip the Obfs4 proxy to the filesystem
in = getObfs4InputStream();
out = new FileOutputStream(obfs4File);
IoUtils.copyAndClose(in, out);
// Make the Obfs4 proxy executable
if (!obfs4File.setExecutable(true, true)) throw new IOException();
// Copy the config file to the filesystem
in = getConfigInputStream();
out = new FileOutputStream(configFile);
IoUtils.copyAndClose(in, out);
doneFile.createNewFile();
} catch (IOException e) {
tryToClose(in);
tryToClose(out);
IoUtils.tryToClose(in, LOG, WARNING);
IoUtils.tryToClose(out, LOG, WARNING);
throw new PluginException(e);
}
}
@@ -314,26 +326,20 @@ abstract class TorPlugin implements DuplexPlugin, EventHandler, EventListener {
return zin;
}
private InputStream getObfs4InputStream() throws IOException {
if (LOG.isLoggable(INFO))
LOG.info("Installing obfs4proxy binary for " + architecture);
InputStream in = resourceProvider
.getResourceInputStream("obfs4proxy_" + architecture, ".zip");
ZipInputStream zin = new ZipInputStream(in);
if (zin.getNextEntry() == null) throw new IOException();
return zin;
}
private InputStream getConfigInputStream() {
return getClass().getClassLoader().getResourceAsStream("torrc");
}
private void tryToClose(@Nullable Closeable c) {
try {
if (c != null) c.close();
} catch (IOException e) {
logException(LOG, WARNING, e);
}
}
private void tryToClose(@Nullable Socket s) {
try {
if (s != null) s.close();
} catch (IOException e) {
logException(LOG, WARNING, e);
}
}
private void listFiles(File f) {
if (f.isDirectory()) {
File[] children = f.listFiles();
@@ -355,7 +361,7 @@ abstract class TorPlugin implements DuplexPlugin, EventHandler, EventListener {
}
return b;
} finally {
tryToClose(in);
IoUtils.tryToClose(in, LOG, WARNING);
}
}
@@ -395,14 +401,9 @@ abstract class TorPlugin implements DuplexPlugin, EventHandler, EventListener {
}
private void tryToClose(@Nullable ServerSocket ss) {
try {
if (ss != null) ss.close();
} catch (IOException e) {
logException(LOG, WARNING, e);
} finally {
IoUtils.tryToClose(ss, LOG, WARNING);
callback.transportDisabled();
}
}
private void publishHiddenService(String port) {
if (!running) return;
@@ -472,6 +473,8 @@ abstract class TorPlugin implements DuplexPlugin, EventHandler, EventListener {
if (enable) {
Collection<String> conf = new ArrayList<>();
conf.add("UseBridges 1");
conf.add("ClientTransportPlugin obfs4 exec " +
obfs4File.getAbsolutePath());
conf.addAll(circumventionProvider.getBridges());
controlConnection.setConf(conf);
} else {
@@ -568,7 +571,7 @@ abstract class TorPlugin implements DuplexPlugin, EventHandler, EventListener {
LOG.info("Could not connect to " + scrubOnion(bestOnion)
+ ": " + e.toString());
}
tryToClose(s);
IoUtils.tryToClose(s, LOG, WARNING);
return null;
}
}
@@ -609,7 +612,8 @@ abstract class TorPlugin implements DuplexPlugin, EventHandler, EventListener {
LOG.info("OR connection " + status + " " + orName);
if (status.equals("CLOSED") || status.equals("FAILED")) {
// Check whether we've lost connectivity
updateConnectionStatus(networkManager.getNetworkStatus());
updateConnectionStatus(networkManager.getNetworkStatus(),
batteryManager.isCharging());
}
}
@@ -647,10 +651,15 @@ abstract class TorPlugin implements DuplexPlugin, EventHandler, EventListener {
// Works around a bug introduced in Tor 0.3.4.8. Could be
// replaced with callback.transportDisabled() when fixed.
disableNetwork();
updateConnectionStatus(networkManager.getNetworkStatus());
updateConnectionStatus(networkManager.getNetworkStatus(),
batteryManager.isCharging());
}
} else if (e instanceof NetworkStatusEvent) {
updateConnectionStatus(((NetworkStatusEvent) e).getStatus());
updateConnectionStatus(((NetworkStatusEvent) e).getStatus(),
batteryManager.isCharging());
} else if (e instanceof BatteryEvent) {
updateConnectionStatus(networkManager.getNetworkStatus(),
((BatteryEvent) e).isCharging());
}
}
@@ -664,7 +673,8 @@ abstract class TorPlugin implements DuplexPlugin, EventHandler, EventListener {
});
}
private void updateConnectionStatus(NetworkStatus status) {
private void updateConnectionStatus(NetworkStatus status,
boolean charging) {
connectionStatusExecutor.execute(() -> {
if (!running) return;
boolean online = status.isConnected();
@@ -682,6 +692,7 @@ abstract class TorPlugin implements DuplexPlugin, EventHandler, EventListener {
LOG.info("Online: " + online + ", wifi: " + wifi);
if ("".equals(country)) LOG.info("Country code unknown");
else LOG.info("Country code: " + country);
LOG.info("Charging: " + charging);
}
try {
@@ -705,12 +716,24 @@ abstract class TorPlugin implements DuplexPlugin, EventHandler, EventListener {
enableBridges(false);
enableNetwork(true);
}
if (online && wifi && charging) {
LOG.info("Enabling connection padding");
enableConnectionPadding(true);
} else {
LOG.info("Disabling connection padding");
enableConnectionPadding(false);
}
} catch (IOException e) {
logException(LOG, WARNING, e);
}
});
}
private void enableConnectionPadding(boolean enable) throws IOException {
if (!running) return;
controlConnection.setConf("ConnectionPadding", enable ? "1" : "0");
}
// TODO remove when sufficient time has passed. Added 2018-08-15
private void migrateSettings() {
Settings sOld = callback.getSettings();
@@ -5,7 +5,7 @@ import org.briarproject.bramble.api.contact.ContactManager;
import org.briarproject.bramble.api.data.MetadataEncoder;
import org.briarproject.bramble.api.lifecycle.LifecycleManager;
import org.briarproject.bramble.api.properties.TransportPropertyManager;
import org.briarproject.bramble.api.sync.ValidationManager;
import org.briarproject.bramble.api.sync.validation.ValidationManager;
import org.briarproject.bramble.api.system.Clock;
import org.briarproject.bramble.api.versioning.ClientVersioningManager;
@@ -24,7 +24,7 @@ import org.briarproject.bramble.api.sync.GroupId;
import org.briarproject.bramble.api.sync.InvalidMessageException;
import org.briarproject.bramble.api.sync.Message;
import org.briarproject.bramble.api.sync.MessageId;
import org.briarproject.bramble.api.sync.ValidationManager.IncomingMessageHook;
import org.briarproject.bramble.api.sync.validation.IncomingMessageHook;
import org.briarproject.bramble.api.system.Clock;
import org.briarproject.bramble.api.versioning.ClientVersioningManager;
import org.briarproject.bramble.api.versioning.ClientVersioningManager.ClientVersioningHook;
@@ -142,15 +142,7 @@ class TransportPropertyManagerImpl implements TransportPropertyManager,
@Override
public Map<TransportId, TransportProperties> getLocalProperties()
throws DbException {
Map<TransportId, TransportProperties> local;
Transaction txn = db.startTransaction(true);
try {
local = getLocalProperties(txn);
db.commitTransaction(txn);
} finally {
db.endTransaction(txn);
}
return local;
return db.transactionWithResult(true, this::getLocalProperties);
}
@Override
@@ -176,9 +168,8 @@ class TransportPropertyManagerImpl implements TransportPropertyManager,
public TransportProperties getLocalProperties(TransportId t)
throws DbException {
try {
return db.transactionWithResult(true, txn -> {
TransportProperties p = null;
Transaction txn = db.startTransaction(true);
try {
// Find the latest local update
LatestUpdate latest = findLatest(txn, localGroup.getId(), t,
true);
@@ -188,11 +179,8 @@ class TransportPropertyManagerImpl implements TransportPropertyManager,
latest.messageId);
p = parseProperties(message);
}
db.commitTransaction(txn);
} finally {
db.endTransaction(txn);
}
return p == null ? new TransportProperties() : p;
});
} catch (FormatException e) {
throw new DbException(e);
}
@@ -201,16 +189,12 @@ class TransportPropertyManagerImpl implements TransportPropertyManager,
@Override
public Map<ContactId, TransportProperties> getRemoteProperties(
TransportId t) throws DbException {
return db.transactionWithResult(true, txn -> {
Map<ContactId, TransportProperties> remote = new HashMap<>();
Transaction txn = db.startTransaction(true);
try {
for (Contact c : db.getContacts(txn))
remote.put(c.getId(), getRemoteProperties(txn, c, t));
db.commitTransaction(txn);
} finally {
db.endTransaction(txn);
}
return remote;
});
}
private TransportProperties getRemoteProperties(Transaction txn, Contact c,
@@ -234,23 +218,15 @@ class TransportPropertyManagerImpl implements TransportPropertyManager,
@Override
public TransportProperties getRemoteProperties(ContactId c, TransportId t)
throws DbException {
TransportProperties p;
Transaction txn = db.startTransaction(true);
try {
p = getRemoteProperties(txn, db.getContact(txn, c), t);
db.commitTransaction(txn);
} finally {
db.endTransaction(txn);
}
return p;
return db.transactionWithResult(true, txn ->
getRemoteProperties(txn, db.getContact(txn, c), t));
}
@Override
public void mergeLocalProperties(TransportId t, TransportProperties p)
throws DbException {
try {
Transaction txn = db.startTransaction(false);
try {
db.transaction(false, txn -> {
// Merge the new properties with any existing properties
TransportProperties merged;
boolean changed;
@@ -287,10 +263,7 @@ class TransportPropertyManagerImpl implements TransportPropertyManager,
db.removeMessage(txn, latest.messageId);
}
}
db.commitTransaction(txn);
} finally {
db.endTransaction(txn);
}
});
} catch (FormatException e) {
throw new DbException(e);
}
@@ -12,7 +12,6 @@ import org.briarproject.bramble.api.reporting.DevReporter;
import org.briarproject.bramble.util.IoUtils;
import org.briarproject.bramble.util.StringUtils;
import java.io.Closeable;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
@@ -26,13 +25,12 @@ import java.net.Socket;
import java.util.concurrent.Executor;
import java.util.logging.Logger;
import javax.annotation.Nullable;
import javax.annotation.concurrent.Immutable;
import javax.inject.Inject;
import javax.net.SocketFactory;
import static java.util.logging.Level.WARNING;
import static org.briarproject.bramble.util.LogUtils.logException;
import static org.briarproject.bramble.util.IoUtils.tryToClose;
@Immutable
@NotNullByDefault
@@ -66,7 +64,7 @@ class DevReporterImpl implements DevReporter, EventListener {
s.setSoTimeout(SOCKET_TIMEOUT);
return s;
} catch (IOException e) {
tryToClose(s);
tryToClose(s, LOG, WARNING);
throw e;
}
}
@@ -88,8 +86,7 @@ class DevReporterImpl implements DevReporter, EventListener {
writer.append(armoured);
writer.flush();
} finally {
if (writer != null)
writer.close();
tryToClose(writer, LOG, WARNING);
}
}
@@ -121,27 +118,11 @@ class DevReporterImpl implements DevReporter, EventListener {
f.delete();
} catch (IOException e) {
LOG.log(WARNING, "Failed to send reports", e);
tryToClose(out);
tryToClose(in);
tryToClose(out, LOG, WARNING);
tryToClose(in, LOG, WARNING);
return;
}
}
LOG.info("Reports sent");
}
private void tryToClose(@Nullable Closeable c) {
try {
if (c != null) c.close();
} catch (IOException e) {
logException(LOG, WARNING, e);
}
}
private void tryToClose(@Nullable Socket s) {
try {
if (s != null) s.close();
} catch (IOException e) {
logException(LOG, WARNING, e);
}
}
}
@@ -23,15 +23,8 @@ class SettingsManagerImpl implements SettingsManager {
@Override
public Settings getSettings(String namespace) throws DbException {
Settings s;
Transaction txn = db.startTransaction(true);
try {
s = db.getSettings(txn, namespace);
db.commitTransaction(txn);
} finally {
db.endTransaction(txn);
}
return s;
return db.transactionWithResult(true, txn ->
db.getSettings(txn, namespace));
}
@Override
@@ -42,12 +35,6 @@ class SettingsManagerImpl implements SettingsManager {
@Override
public void mergeSettings(Settings s, String namespace) throws DbException {
Transaction txn = db.startTransaction(false);
try {
db.mergeSettings(txn, s, namespace);
db.commitTransaction(txn);
} finally {
db.endTransaction(txn);
}
db.transaction(false, txn -> db.mergeSettings(txn, s, namespace));
}
}
@@ -5,7 +5,6 @@ import org.briarproject.bramble.api.contact.event.ContactRemovedEvent;
import org.briarproject.bramble.api.db.DatabaseComponent;
import org.briarproject.bramble.api.db.DatabaseExecutor;
import org.briarproject.bramble.api.db.DbException;
import org.briarproject.bramble.api.db.Transaction;
import org.briarproject.bramble.api.event.Event;
import org.briarproject.bramble.api.event.EventBus;
import org.briarproject.bramble.api.event.EventListener;
@@ -230,14 +229,8 @@ class DuplexOutgoingSession implements SyncSession, EventListener {
if (interrupted) return;
if (!generateAckQueued.getAndSet(false)) throw new AssertionError();
try {
Ack a;
Transaction txn = db.startTransaction(false);
try {
a = db.generateAck(txn, contactId, MAX_MESSAGE_IDS);
db.commitTransaction(txn);
} finally {
db.endTransaction(txn);
}
Ack a = db.transactionWithNullableResult(false, txn ->
db.generateAck(txn, contactId, MAX_MESSAGE_IDS));
if (LOG.isLoggable(INFO))
LOG.info("Generated ack: " + (a != null));
if (a != null) writerTasks.add(new WriteAck(a));
@@ -275,16 +268,15 @@ class DuplexOutgoingSession implements SyncSession, EventListener {
if (!generateBatchQueued.getAndSet(false))
throw new AssertionError();
try {
Collection<Message> b;
Transaction txn = db.startTransaction(false);
try {
b = db.generateRequestedBatch(txn, contactId,
MAX_RECORD_PAYLOAD_BYTES, maxLatency);
Collection<Message> b =
db.transactionWithNullableResult(false, txn -> {
Collection<Message> batch =
db.generateRequestedBatch(txn, contactId,
MAX_RECORD_PAYLOAD_BYTES,
maxLatency);
setNextSendTime(db.getNextSendTime(txn, contactId));
db.commitTransaction(txn);
} finally {
db.endTransaction(txn);
}
return batch;
});
if (LOG.isLoggable(INFO))
LOG.info("Generated batch: " + (b != null));
if (b != null) writerTasks.add(new WriteBatch(b));
@@ -322,16 +314,12 @@ class DuplexOutgoingSession implements SyncSession, EventListener {
if (!generateOfferQueued.getAndSet(false))
throw new AssertionError();
try {
Offer o;
Transaction txn = db.startTransaction(false);
try {
o = db.generateOffer(txn, contactId, MAX_MESSAGE_IDS,
maxLatency);
Offer o = db.transactionWithNullableResult(false, txn -> {
Offer offer = db.generateOffer(txn, contactId,
MAX_MESSAGE_IDS, maxLatency);
setNextSendTime(db.getNextSendTime(txn, contactId));
db.commitTransaction(txn);
} finally {
db.endTransaction(txn);
}
return offer;
});
if (LOG.isLoggable(INFO))
LOG.info("Generated offer: " + (o != null));
if (o != null) writerTasks.add(new WriteOffer(o));
@@ -369,14 +357,8 @@ class DuplexOutgoingSession implements SyncSession, EventListener {
if (!generateRequestQueued.getAndSet(false))
throw new AssertionError();
try {
Request r;
Transaction txn = db.startTransaction(false);
try {
r = db.generateRequest(txn, contactId, MAX_MESSAGE_IDS);
db.commitTransaction(txn);
} finally {
db.endTransaction(txn);
}
Request r = db.transactionWithNullableResult(false, txn ->
db.generateRequest(txn, contactId, MAX_MESSAGE_IDS));
if (LOG.isLoggable(INFO))
LOG.info("Generated request: " + (r != null));
if (r != null) writerTasks.add(new WriteRequest(r));
@@ -6,7 +6,6 @@ import org.briarproject.bramble.api.contact.event.ContactRemovedEvent;
import org.briarproject.bramble.api.db.DatabaseComponent;
import org.briarproject.bramble.api.db.DatabaseExecutor;
import org.briarproject.bramble.api.db.DbException;
import org.briarproject.bramble.api.db.Transaction;
import org.briarproject.bramble.api.event.Event;
import org.briarproject.bramble.api.event.EventBus;
import org.briarproject.bramble.api.event.EventListener;
@@ -120,13 +119,8 @@ class IncomingSession implements SyncSession, EventListener {
@Override
public void run() {
try {
Transaction txn = db.startTransaction(false);
try {
db.receiveAck(txn, contactId, ack);
db.commitTransaction(txn);
} finally {
db.endTransaction(txn);
}
db.transaction(false, txn ->
db.receiveAck(txn, contactId, ack));
} catch (DbException e) {
logException(LOG, WARNING, e);
interrupt();
@@ -146,13 +140,8 @@ class IncomingSession implements SyncSession, EventListener {
@Override
public void run() {
try {
Transaction txn = db.startTransaction(false);
try {
db.receiveMessage(txn, contactId, message);
db.commitTransaction(txn);
} finally {
db.endTransaction(txn);
}
db.transaction(false, txn ->
db.receiveMessage(txn, contactId, message));
} catch (DbException e) {
logException(LOG, WARNING, e);
interrupt();
@@ -172,13 +161,8 @@ class IncomingSession implements SyncSession, EventListener {
@Override
public void run() {
try {
Transaction txn = db.startTransaction(false);
try {
db.receiveOffer(txn, contactId, offer);
db.commitTransaction(txn);
} finally {
db.endTransaction(txn);
}
db.transaction(false, txn ->
db.receiveOffer(txn, contactId, offer));
} catch (DbException e) {
logException(LOG, WARNING, e);
interrupt();
@@ -198,13 +182,8 @@ class IncomingSession implements SyncSession, EventListener {
@Override
public void run() {
try {
Transaction txn = db.startTransaction(false);
try {
db.receiveRequest(txn, contactId, request);
db.commitTransaction(txn);
} finally {
db.endTransaction(txn);
}
db.transaction(false, txn ->
db.receiveRequest(txn, contactId, request));
} catch (DbException e) {
logException(LOG, WARNING, e);
interrupt();
@@ -5,7 +5,6 @@ import org.briarproject.bramble.api.contact.event.ContactRemovedEvent;
import org.briarproject.bramble.api.db.DatabaseComponent;
import org.briarproject.bramble.api.db.DatabaseExecutor;
import org.briarproject.bramble.api.db.DbException;
import org.briarproject.bramble.api.db.Transaction;
import org.briarproject.bramble.api.event.Event;
import org.briarproject.bramble.api.event.EventBus;
import org.briarproject.bramble.api.event.EventListener;
@@ -47,7 +46,8 @@ class SimplexOutgoingSession implements SyncSession, EventListener {
private static final Logger LOG =
Logger.getLogger(SimplexOutgoingSession.class.getName());
private static final ThrowingRunnable<IOException> CLOSE = () -> {};
private static final ThrowingRunnable<IOException> CLOSE = () -> {
};
private final DatabaseComponent db;
private final Executor dbExecutor;
@@ -128,14 +128,8 @@ class SimplexOutgoingSession implements SyncSession, EventListener {
public void run() {
if (interrupted) return;
try {
Ack a;
Transaction txn = db.startTransaction(false);
try {
a = db.generateAck(txn, contactId, MAX_MESSAGE_IDS);
db.commitTransaction(txn);
} finally {
db.endTransaction(txn);
}
Ack a = db.transactionWithNullableResult(false, txn ->
db.generateAck(txn, contactId, MAX_MESSAGE_IDS));
if (LOG.isLoggable(INFO))
LOG.info("Generated ack: " + (a != null));
if (a == null) decrementOutstandingQueries();
@@ -172,15 +166,10 @@ class SimplexOutgoingSession implements SyncSession, EventListener {
public void run() {
if (interrupted) return;
try {
Collection<Message> b;
Transaction txn = db.startTransaction(false);
try {
b = db.generateBatch(txn, contactId,
MAX_RECORD_PAYLOAD_BYTES, maxLatency);
db.commitTransaction(txn);
} finally {
db.endTransaction(txn);
}
Collection<Message> b =
db.transactionWithNullableResult(false, txn ->
db.generateBatch(txn, contactId,
MAX_RECORD_PAYLOAD_BYTES, maxLatency));
if (LOG.isLoggable(INFO))
LOG.info("Generated batch: " + (b != null));
if (b == null) decrementOutstandingQueries();
@@ -1,23 +1,11 @@
package org.briarproject.bramble.sync;
import org.briarproject.bramble.PoliteExecutor;
import org.briarproject.bramble.api.crypto.CryptoComponent;
import org.briarproject.bramble.api.crypto.CryptoExecutor;
import org.briarproject.bramble.api.db.DatabaseComponent;
import org.briarproject.bramble.api.db.DatabaseExecutor;
import org.briarproject.bramble.api.event.EventBus;
import org.briarproject.bramble.api.lifecycle.LifecycleManager;
import org.briarproject.bramble.api.sync.GroupFactory;
import org.briarproject.bramble.api.sync.MessageFactory;
import org.briarproject.bramble.api.sync.SyncRecordReaderFactory;
import org.briarproject.bramble.api.sync.SyncRecordWriterFactory;
import org.briarproject.bramble.api.sync.SyncSessionFactory;
import org.briarproject.bramble.api.sync.ValidationManager;
import org.briarproject.bramble.api.system.Clock;
import java.util.concurrent.Executor;
import javax.inject.Inject;
import javax.inject.Singleton;
import dagger.Module;
@@ -26,29 +14,14 @@ import dagger.Provides;
@Module
public class SyncModule {
public static class EagerSingletons {
@Inject
ValidationManager validationManager;
}
/**
* The maximum number of validation tasks to delegate to the crypto
* executor concurrently.
* <p>
* The number of available processors can change during the lifetime of the
* JVM, so this is just a reasonable guess.
*/
private static final int MAX_CONCURRENT_VALIDATION_TASKS =
Math.max(1, Runtime.getRuntime().availableProcessors() - 1);
@Provides
GroupFactory provideGroupFactory(CryptoComponent crypto) {
return new GroupFactoryImpl(crypto);
GroupFactory provideGroupFactory(GroupFactoryImpl groupFactory) {
return groupFactory;
}
@Provides
MessageFactory provideMessageFactory(CryptoComponent crypto) {
return new MessageFactoryImpl(crypto);
MessageFactory provideMessageFactory(MessageFactoryImpl messageFactory) {
return messageFactory;
}
@Provides
@@ -65,30 +38,8 @@ public class SyncModule {
@Provides
@Singleton
SyncSessionFactory provideSyncSessionFactory(DatabaseComponent db,
@DatabaseExecutor Executor dbExecutor, EventBus eventBus,
Clock clock, SyncRecordReaderFactory recordReaderFactory,
SyncRecordWriterFactory recordWriterFactory) {
return new SyncSessionFactoryImpl(db, dbExecutor, eventBus, clock,
recordReaderFactory, recordWriterFactory);
}
@Provides
@Singleton
ValidationManager provideValidationManager(
LifecycleManager lifecycleManager, EventBus eventBus,
ValidationManagerImpl validationManager) {
lifecycleManager.registerService(validationManager);
eventBus.addListener(validationManager);
return validationManager;
}
@Provides
@Singleton
@ValidationExecutor
Executor provideValidationExecutor(
@CryptoExecutor Executor cryptoExecutor) {
return new PoliteExecutor("ValidationExecutor", cryptoExecutor,
MAX_CONCURRENT_VALIDATION_TASKS);
SyncSessionFactory provideSyncSessionFactory(
SyncSessionFactoryImpl syncSessionFactory) {
return syncSessionFactory;
}
}
@@ -1,4 +1,4 @@
package org.briarproject.bramble.sync;
package org.briarproject.bramble.sync.validation;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
@@ -1,5 +1,6 @@
package org.briarproject.bramble.sync;
package org.briarproject.bramble.sync.validation;
import org.briarproject.bramble.api.Pair;
import org.briarproject.bramble.api.db.DatabaseComponent;
import org.briarproject.bramble.api.db.DatabaseExecutor;
import org.briarproject.bramble.api.db.DbException;
@@ -17,8 +18,11 @@ import org.briarproject.bramble.api.sync.InvalidMessageException;
import org.briarproject.bramble.api.sync.Message;
import org.briarproject.bramble.api.sync.MessageContext;
import org.briarproject.bramble.api.sync.MessageId;
import org.briarproject.bramble.api.sync.ValidationManager;
import org.briarproject.bramble.api.sync.event.MessageAddedEvent;
import org.briarproject.bramble.api.sync.validation.IncomingMessageHook;
import org.briarproject.bramble.api.sync.validation.MessageState;
import org.briarproject.bramble.api.sync.validation.MessageValidator;
import org.briarproject.bramble.api.sync.validation.ValidationManager;
import org.briarproject.bramble.api.versioning.ClientMajorVersion;
import java.util.Collection;
@@ -36,9 +40,9 @@ import javax.inject.Inject;
import static java.util.logging.Level.INFO;
import static java.util.logging.Level.WARNING;
import static org.briarproject.bramble.api.sync.ValidationManager.State.DELIVERED;
import static org.briarproject.bramble.api.sync.ValidationManager.State.INVALID;
import static org.briarproject.bramble.api.sync.ValidationManager.State.PENDING;
import static org.briarproject.bramble.api.sync.validation.MessageState.DELIVERED;
import static org.briarproject.bramble.api.sync.validation.MessageState.INVALID;
import static org.briarproject.bramble.api.sync.validation.MessageState.PENDING;
import static org.briarproject.bramble.util.LogUtils.logException;
@ThreadSafe
@@ -97,14 +101,8 @@ class ValidationManagerImpl implements ValidationManager, Service,
@DatabaseExecutor
private void validateOutstandingMessages() {
try {
Queue<MessageId> unvalidated = new LinkedList<>();
Transaction txn = db.startTransaction(true);
try {
unvalidated.addAll(db.getMessagesToValidate(txn));
db.commitTransaction(txn);
} finally {
db.endTransaction(txn);
}
Queue<MessageId> unvalidated = new LinkedList<>(
db.transactionWithResult(true, db::getMessagesToValidate));
validateNextMessageAsync(unvalidated);
} catch (DbException e) {
logException(LOG, WARNING, e);
@@ -119,18 +117,14 @@ class ValidationManagerImpl implements ValidationManager, Service,
@DatabaseExecutor
private void validateNextMessage(Queue<MessageId> unvalidated) {
try {
Message m;
Group g;
Transaction txn = db.startTransaction(true);
try {
Pair<Message, Group> mg = db.transactionWithResult(true, txn -> {
MessageId id = unvalidated.poll();
m = db.getMessage(txn, id);
g = db.getGroup(txn, m.getGroupId());
db.commitTransaction(txn);
} finally {
db.endTransaction(txn);
}
validateMessageAsync(m, g);
if (id == null) throw new AssertionError();
Message m = db.getMessage(txn, id);
Group g = db.getGroup(txn, m.getGroupId());
return new Pair<>(m, g);
});
validateMessageAsync(mg.getFirst(), mg.getSecond());
validateNextMessageAsync(unvalidated);
} catch (NoSuchMessageException e) {
LOG.info("Message removed before validation");
@@ -150,14 +144,8 @@ class ValidationManagerImpl implements ValidationManager, Service,
@DatabaseExecutor
private void deliverOutstandingMessages() {
try {
Queue<MessageId> pending = new LinkedList<>();
Transaction txn = db.startTransaction(true);
try {
pending.addAll(db.getPendingMessages(txn));
db.commitTransaction(txn);
} finally {
db.endTransaction(txn);
}
Queue<MessageId> pending = new LinkedList<>(
db.transactionWithResult(true, db::getPendingMessages));
deliverNextPendingMessageAsync(pending);
} catch (DbException e) {
logException(LOG, WARNING, e);
@@ -172,24 +160,24 @@ class ValidationManagerImpl implements ValidationManager, Service,
@DatabaseExecutor
private void deliverNextPendingMessage(Queue<MessageId> pending) {
try {
Queue<MessageId> toShare = new LinkedList<>();
Queue<MessageId> invalidate = new LinkedList<>();
db.transaction(false, txn -> {
boolean anyInvalid = false, allDelivered = true;
Queue<MessageId> toShare = null;
Queue<MessageId> invalidate = null;
Transaction txn = db.startTransaction(false);
try {
MessageId id = pending.poll();
if (id == null) throw new AssertionError();
// Check if message is still pending
if (db.getMessageState(txn, id) == PENDING) {
// Check if dependencies are valid and delivered
Map<MessageId, State> states =
Map<MessageId, MessageState> states =
db.getMessageDependencies(txn, id);
for (Entry<MessageId, State> e : states.entrySet()) {
for (Entry<MessageId, MessageState> e : states.entrySet()) {
if (e.getValue() == INVALID) anyInvalid = true;
if (e.getValue() != DELIVERED) allDelivered = false;
}
if (anyInvalid) {
invalidateMessage(txn, id);
invalidate = getDependentsToInvalidate(txn, id);
addDependentsToInvalidate(txn, id, invalidate);
} else if (allDelivered) {
Message m = db.getMessage(txn, id);
Group g = db.getGroup(txn, m.getGroupId());
@@ -200,22 +188,19 @@ class ValidationManagerImpl implements ValidationManager, Service,
DeliveryResult result =
deliverMessage(txn, m, c, majorVersion, meta);
if (result.valid) {
pending.addAll(getPendingDependents(txn, id));
addPendingDependents(txn, id, pending);
if (result.share) {
db.setMessageShared(txn, id);
toShare = new LinkedList<>(states.keySet());
toShare.addAll(states.keySet());
}
} else {
invalidate = getDependentsToInvalidate(txn, id);
addDependentsToInvalidate(txn, id, invalidate);
}
}
}
db.commitTransaction(txn);
} finally {
db.endTransaction(txn);
}
if (invalidate != null) invalidateNextMessageAsync(invalidate);
if (toShare != null) shareNextMessageAsync(toShare);
});
if (!invalidate.isEmpty()) invalidateNextMessageAsync(invalidate);
if (!toShare.isEmpty()) shareNextMessageAsync(toShare);
deliverNextPendingMessageAsync(pending);
} catch (NoSuchMessageException e) {
LOG.info("Message removed before delivery");
@@ -264,20 +249,19 @@ class ValidationManagerImpl implements ValidationManager, Service,
MessageContext context) {
try {
MessageId id = m.getId();
Queue<MessageId> invalidate = new LinkedList<>();
Queue<MessageId> pending = new LinkedList<>();
Queue<MessageId> toShare = new LinkedList<>();
db.transaction(false, txn -> {
boolean anyInvalid = false, allDelivered = true;
Queue<MessageId> invalidate = null;
Queue<MessageId> pending = null;
Queue<MessageId> toShare = null;
Transaction txn = db.startTransaction(false);
try {
// Check if message has any dependencies
Collection<MessageId> dependencies = context.getDependencies();
if (!dependencies.isEmpty()) {
db.addMessageDependencies(txn, m, dependencies);
// Check if dependencies are valid and delivered
Map<MessageId, State> states =
Map<MessageId, MessageState> states =
db.getMessageDependencies(txn, id);
for (Entry<MessageId, State> e : states.entrySet()) {
for (Entry<MessageId, MessageState> e : states.entrySet()) {
if (e.getValue() == INVALID) anyInvalid = true;
if (e.getValue() != DELIVERED) allDelivered = false;
}
@@ -285,7 +269,7 @@ class ValidationManagerImpl implements ValidationManager, Service,
if (anyInvalid) {
if (db.getMessageState(txn, id) != INVALID) {
invalidateMessage(txn, id);
invalidate = getDependentsToInvalidate(txn, id);
addDependentsToInvalidate(txn, id, invalidate);
}
} else {
Metadata meta = context.getMetadata();
@@ -294,25 +278,22 @@ class ValidationManagerImpl implements ValidationManager, Service,
DeliveryResult result =
deliverMessage(txn, m, c, majorVersion, meta);
if (result.valid) {
pending = getPendingDependents(txn, id);
addPendingDependents(txn, id, pending);
if (result.share) {
db.setMessageShared(txn, id);
toShare = new LinkedList<>(dependencies);
toShare.addAll(dependencies);
}
} else {
invalidate = getDependentsToInvalidate(txn, id);
addDependentsToInvalidate(txn, id, invalidate);
}
} else {
db.setMessageState(txn, id, PENDING);
}
}
db.commitTransaction(txn);
} finally {
db.endTransaction(txn);
}
if (invalidate != null) invalidateNextMessageAsync(invalidate);
if (pending != null) deliverNextPendingMessageAsync(pending);
if (toShare != null) shareNextMessageAsync(toShare);
});
if (!invalidate.isEmpty()) invalidateNextMessageAsync(invalidate);
if (!pending.isEmpty()) deliverNextPendingMessageAsync(pending);
if (!toShare.isEmpty()) shareNextMessageAsync(toShare);
} catch (NoSuchMessageException e) {
LOG.info("Message removed during validation");
} catch (NoSuchGroupException e) {
@@ -342,14 +323,12 @@ class ValidationManagerImpl implements ValidationManager, Service,
}
@DatabaseExecutor
private Queue<MessageId> getPendingDependents(Transaction txn, MessageId m)
throws DbException {
Queue<MessageId> pending = new LinkedList<>();
Map<MessageId, State> states = db.getMessageDependents(txn, m);
for (Entry<MessageId, State> e : states.entrySet()) {
private void addPendingDependents(Transaction txn, MessageId m,
Queue<MessageId> pending) throws DbException {
Map<MessageId, MessageState> states = db.getMessageDependents(txn, m);
for (Entry<MessageId, MessageState> e : states.entrySet()) {
if (e.getValue() == PENDING) pending.add(e.getKey());
}
return pending;
}
private void shareOutstandingMessagesAsync() {
@@ -359,14 +338,8 @@ class ValidationManagerImpl implements ValidationManager, Service,
@DatabaseExecutor
private void shareOutstandingMessages() {
try {
Queue<MessageId> toShare = new LinkedList<>();
Transaction txn = db.startTransaction(true);
try {
toShare.addAll(db.getMessagesToShare(txn));
db.commitTransaction(txn);
} finally {
db.endTransaction(txn);
}
Queue<MessageId> toShare = new LinkedList<>(
db.transactionWithResult(true, db::getMessagesToShare));
shareNextMessageAsync(toShare);
} catch (DbException e) {
logException(LOG, WARNING, e);
@@ -387,15 +360,12 @@ class ValidationManagerImpl implements ValidationManager, Service,
@DatabaseExecutor
private void shareNextMessage(Queue<MessageId> toShare) {
try {
Transaction txn = db.startTransaction(false);
try {
db.transaction(false, txn -> {
MessageId id = toShare.poll();
if (id == null) throw new AssertionError();
db.setMessageShared(txn, id);
toShare.addAll(db.getMessageDependencies(txn, id).keySet());
db.commitTransaction(txn);
} finally {
db.endTransaction(txn);
}
});
shareNextMessageAsync(toShare);
} catch (NoSuchMessageException e) {
LOG.info("Message removed before sharing");
@@ -416,17 +386,14 @@ class ValidationManagerImpl implements ValidationManager, Service,
@DatabaseExecutor
private void invalidateNextMessage(Queue<MessageId> invalidate) {
try {
Transaction txn = db.startTransaction(false);
try {
db.transaction(false, txn -> {
MessageId id = invalidate.poll();
if (id == null) throw new AssertionError();
if (db.getMessageState(txn, id) != INVALID) {
invalidateMessage(txn, id);
invalidate.addAll(getDependentsToInvalidate(txn, id));
}
db.commitTransaction(txn);
} finally {
db.endTransaction(txn);
addDependentsToInvalidate(txn, id, invalidate);
}
});
invalidateNextMessageAsync(invalidate);
} catch (NoSuchMessageException e) {
LOG.info("Message removed before invalidation");
@@ -445,14 +412,12 @@ class ValidationManagerImpl implements ValidationManager, Service,
}
@DatabaseExecutor
private Queue<MessageId> getDependentsToInvalidate(Transaction txn,
MessageId m) throws DbException {
Queue<MessageId> invalidate = new LinkedList<>();
Map<MessageId, State> states = db.getMessageDependents(txn, m);
for (Entry<MessageId, State> e : states.entrySet()) {
private void addDependentsToInvalidate(Transaction txn,
MessageId m, Queue<MessageId> invalidate) throws DbException {
Map<MessageId, MessageState> states = db.getMessageDependents(txn, m);
for (Entry<MessageId, MessageState> e : states.entrySet()) {
if (e.getValue() != INVALID) invalidate.add(e.getKey());
}
return invalidate;
}
@Override
@@ -472,14 +437,8 @@ class ValidationManagerImpl implements ValidationManager, Service,
@DatabaseExecutor
private void loadGroupAndValidate(Message m) {
try {
Group g;
Transaction txn = db.startTransaction(true);
try {
g = db.getGroup(txn, m.getGroupId());
db.commitTransaction(txn);
} finally {
db.endTransaction(txn);
}
Group g = db.transactionWithResult(true, txn ->
db.getGroup(txn, m.getGroupId()));
validateMessageAsync(m, g);
} catch (NoSuchGroupException e) {
LOG.info("Group removed before validation");
@@ -0,0 +1,53 @@
package org.briarproject.bramble.sync.validation;
import org.briarproject.bramble.PoliteExecutor;
import org.briarproject.bramble.api.crypto.CryptoExecutor;
import org.briarproject.bramble.api.event.EventBus;
import org.briarproject.bramble.api.lifecycle.LifecycleManager;
import org.briarproject.bramble.api.sync.validation.ValidationManager;
import java.util.concurrent.Executor;
import javax.inject.Inject;
import javax.inject.Singleton;
import dagger.Module;
import dagger.Provides;
@Module
public class ValidationModule {
public static class EagerSingletons {
@Inject
ValidationManager validationManager;
}
/**
* The maximum number of validation tasks to delegate to the crypto
* executor concurrently.
* <p>
* The number of available processors can change during the lifetime of the
* JVM, so this is just a reasonable guess.
*/
private static final int MAX_CONCURRENT_VALIDATION_TASKS =
Math.max(1, Runtime.getRuntime().availableProcessors() - 1);
@Provides
@Singleton
ValidationManager provideValidationManager(
LifecycleManager lifecycleManager, EventBus eventBus,
ValidationManagerImpl validationManager) {
lifecycleManager.registerService(validationManager);
eventBus.addListener(validationManager);
return validationManager;
}
@Provides
@Singleton
@ValidationExecutor
Executor provideValidationExecutor(
@CryptoExecutor Executor cryptoExecutor) {
return new PoliteExecutor("ValidationExecutor", cryptoExecutor,
MAX_CONCURRENT_VALIDATION_TASKS);
}
}
@@ -13,32 +13,33 @@ import java.util.logging.Logger;
import javax.annotation.concurrent.Immutable;
import static java.util.logging.Level.WARNING;
import static java.util.logging.Logger.getLogger;
import static org.briarproject.bramble.util.LogUtils.logException;
@Immutable
@NotNullByDefault
class LinuxSecureRandomProvider extends AbstractSecureRandomProvider {
class UnixSecureRandomProvider extends AbstractSecureRandomProvider {
private static final Logger LOG =
Logger.getLogger(LinuxSecureRandomProvider.class.getName());
getLogger(UnixSecureRandomProvider.class.getName());
private static final File RANDOM_DEVICE = new File("/dev/urandom");
private final AtomicBoolean seeded = new AtomicBoolean(false);
private final File outputDevice;
LinuxSecureRandomProvider() {
UnixSecureRandomProvider() {
this(RANDOM_DEVICE);
}
LinuxSecureRandomProvider(File outputDevice) {
UnixSecureRandomProvider(File outputDevice) {
this.outputDevice = outputDevice;
}
@Override
public Provider getProvider() {
if (!seeded.getAndSet(true)) writeSeed();
return new LinuxProvider();
return new UnixProvider();
}
protected void writeSeed() {
@@ -55,15 +56,15 @@ class LinuxSecureRandomProvider extends AbstractSecureRandomProvider {
}
// Based on https://android-developers.googleblog.com/2013/08/some-securerandom-thoughts.html
private static class LinuxProvider extends Provider {
private static class UnixProvider extends Provider {
private LinuxProvider() {
super("LinuxPRNG", 1.1, "A Linux-specific PRNG using /dev/urandom");
private UnixProvider() {
super("UnixPRNG", 1.0, "A Unix-specific PRNG using /dev/urandom");
// Although /dev/urandom is not a SHA-1 PRNG, some callers
// explicitly request a SHA1PRNG SecureRandom and we need to
// prevent them from getting the default implementation whose
// output may have low entropy.
put("SecureRandom.SHA1PRNG", LinuxSecureRandomSpi.class.getName());
put("SecureRandom.SHA1PRNG", UnixSecureRandomSpi.class.getName());
put("SecureRandom.SHA1PRNG ImplementedIn", "Software");
}
}
@@ -10,22 +10,24 @@ import java.security.SecureRandomSpi;
import java.util.logging.Logger;
import static java.util.logging.Level.WARNING;
import static java.util.logging.Logger.getLogger;
import static org.briarproject.bramble.util.LogUtils.logException;
public class LinuxSecureRandomSpi extends SecureRandomSpi {
public class UnixSecureRandomSpi extends SecureRandomSpi {
private static final Logger LOG =
Logger.getLogger(LinuxSecureRandomSpi.class.getName());
getLogger(UnixSecureRandomSpi.class.getName());
private static final File RANDOM_DEVICE = new File("/dev/urandom");
private final File inputDevice, outputDevice;
public LinuxSecureRandomSpi() {
@SuppressWarnings("WeakerAccess")
public UnixSecureRandomSpi() {
this(RANDOM_DEVICE, RANDOM_DEVICE);
}
LinuxSecureRandomSpi(File inputDevice, File outputDevice) {
UnixSecureRandomSpi(File inputDevice, File outputDevice) {
this.inputDevice = inputDevice;
this.outputDevice = outputDevice;
}
@@ -72,8 +72,7 @@ class KeyManagerImpl implements KeyManager, Service, EventListener {
for (DuplexPluginFactory f : pluginConfig.getDuplexFactories())
transports.put(f.getId(), f.getMaxLatency());
try {
Transaction txn = db.startTransaction(false);
try {
db.transaction(false, txn -> {
for (Contact c : db.getContacts(txn))
if (c.isActive()) activeContacts.put(c.getId(), true);
for (Entry<TransportId, Integer> e : transports.entrySet())
@@ -85,10 +84,7 @@ class KeyManagerImpl implements KeyManager, Service, EventListener {
managers.put(e.getKey(), m);
m.start(txn);
}
db.commitTransaction(txn);
} finally {
db.endTransaction(txn);
}
});
} catch (DbException e) {
throw new ServiceException(e);
}
@@ -141,15 +137,8 @@ class KeyManagerImpl implements KeyManager, Service, EventListener {
if (LOG.isLoggable(INFO)) LOG.info("No key manager for " + t);
return null;
}
StreamContext ctx;
Transaction txn = db.startTransaction(false);
try {
ctx = m.getStreamContext(txn, c);
db.commitTransaction(txn);
} finally {
db.endTransaction(txn);
}
return ctx;
return db.transactionWithNullableResult(false, txn ->
m.getStreamContext(txn, c));
}
@Override
@@ -160,15 +149,8 @@ class KeyManagerImpl implements KeyManager, Service, EventListener {
if (LOG.isLoggable(INFO)) LOG.info("No key manager for " + t);
return null;
}
StreamContext ctx;
Transaction txn = db.startTransaction(false);
try {
ctx = m.getStreamContext(txn, tag);
db.commitTransaction(txn);
} finally {
db.endTransaction(txn);
}
return ctx;
return db.transactionWithNullableResult(false, txn ->
m.getStreamContext(txn, tag));
}
@Override
@@ -162,13 +162,7 @@ class TransportKeyManagerImpl implements TransportKeyManager {
private void rotateKeys() {
dbExecutor.execute(() -> {
try {
Transaction txn = db.startTransaction(false);
try {
rotateKeys(txn);
db.commitTransaction(txn);
} finally {
db.endTransaction(txn);
}
db.transaction(false, this::rotateKeys);
} catch (DbException e) {
logException(LOG, WARNING, e);
}
@@ -23,7 +23,7 @@ import org.briarproject.bramble.api.sync.GroupId;
import org.briarproject.bramble.api.sync.InvalidMessageException;
import org.briarproject.bramble.api.sync.Message;
import org.briarproject.bramble.api.sync.MessageId;
import org.briarproject.bramble.api.sync.ValidationManager.IncomingMessageHook;
import org.briarproject.bramble.api.sync.validation.IncomingMessageHook;
import org.briarproject.bramble.api.system.Clock;
import org.briarproject.bramble.api.versioning.ClientMajorVersion;
import org.briarproject.bramble.api.versioning.ClientVersioningManager;
@@ -89,14 +89,9 @@ class ClientVersioningManagerImpl implements ClientVersioningManager, Client,
public Visibility getClientVisibility(Transaction txn, ContactId contactId,
ClientId clientId, int majorVersion) throws DbException {
try {
Contact contact = db.getContact(txn, contactId);
Group g = getContactGroup(contact);
// Contact may be in the process of being added or removed, so
// contact group may not exist
if (!db.containsGroup(txn, g.getId())) return INVISIBLE;
LatestUpdates latest = findLatestUpdates(txn, g.getId());
LatestUpdates latest = findLatestUpdates(txn, contactId);
if (latest == null || latest.remote == null) return INVISIBLE;
if (latest.local == null) throw new DbException();
if (latest.remote == null) return INVISIBLE;
Update localUpdate = loadUpdate(txn, latest.local.messageId);
Update remoteUpdate = loadUpdate(txn, latest.remote.messageId);
Map<ClientMajorVersion, Visibility> visibilities =
@@ -110,6 +105,24 @@ class ClientVersioningManagerImpl implements ClientVersioningManager, Client,
}
}
@Override
public int getClientMinorVersion(Transaction txn, ContactId contactId,
ClientId clientId, int majorVersion) throws DbException {
try {
LatestUpdates latest = findLatestUpdates(txn, contactId);
if (latest == null || latest.remote == null) return -1;
Update remoteUpdate = loadUpdate(txn, latest.remote.messageId);
ClientMajorVersion cv =
new ClientMajorVersion(clientId, majorVersion);
for (ClientState remote : remoteUpdate.states) {
if (remote.majorVersion.equals(cv)) return remote.minorVersion;
}
return -1;
} catch (FormatException e) {
throw new DbException(e);
}
}
@Override
public void createLocalState(Transaction txn) throws DbException {
if (db.containsGroup(txn, localGroup.getId())) return;
@@ -123,16 +136,12 @@ class ClientVersioningManagerImpl implements ClientVersioningManager, Client,
List<ClientVersion> versions = new ArrayList<>(clients);
Collections.sort(versions);
try {
Transaction txn = db.startTransaction(false);
try {
db.transaction(false, txn -> {
if (updateClientVersions(txn, versions)) {
for (Contact c : db.getContacts(txn))
clientVersionsUpdated(txn, c, versions);
}
db.commitTransaction(txn);
} finally {
db.endTransaction(txn);
}
});
} catch (DbException e) {
throw new ServiceException(e);
}
@@ -340,6 +349,17 @@ class ClientVersioningManagerImpl implements ClientVersioningManager, Client,
MAJOR_VERSION, c);
}
@Nullable
private LatestUpdates findLatestUpdates(Transaction txn, ContactId c)
throws DbException, FormatException {
Contact contact = db.getContact(txn, c);
Group g = getContactGroup(contact);
// Contact may be in the process of being added or removed, so
// contact group may not exist
if (!db.containsGroup(txn, g.getId())) return null;
return findLatestUpdates(txn, g.getId());
}
private LatestUpdates findLatestUpdates(Transaction txn, GroupId g)
throws DbException, FormatException {
Map<MessageId, BdfDictionary> metadata =
@@ -4,7 +4,7 @@ import org.briarproject.bramble.api.client.ClientHelper;
import org.briarproject.bramble.api.contact.ContactManager;
import org.briarproject.bramble.api.data.MetadataEncoder;
import org.briarproject.bramble.api.lifecycle.LifecycleManager;
import org.briarproject.bramble.api.sync.ValidationManager;
import org.briarproject.bramble.api.sync.validation.ValidationManager;
import org.briarproject.bramble.api.system.Clock;
import org.briarproject.bramble.api.versioning.ClientVersioningManager;
+4 -8
View File
@@ -1,8 +1,4 @@
Bridge 131.252.210.150:8081 0E858AC201BF0F3FA3C462F64844CBFFC7297A42
Bridge 67.205.189.122:8443 12D64D5D44E20169585E7378580C0D33A872AD98
Bridge 45.32.148.146:8443 0CE016FB2462D8BF179AE71F7D702D09DEAC3F1D
Bridge 148.251.90.59:7510 019F727CA6DCA6CA5C90B55E477B7D87981E75BC
Bridge 45.55.1.74:8443 6F18FEFBB0CAECD5ABA755312FCCB34FC11A7AB8
Bridge 85.229.131.78:444 50E433CCC5FEC11CC34CB4D92033561E065EA106
Bridge 178.62.62.193:8443 391B1F9B6A28A1C5FAE1872283985F975E5DB029
Bridge 45.76.29.92:8443 ECF1DD51A46FDEF2C50CED992EEEAE8DED18DA0C
Bridge obfs4 78.46.188.239:37356 5A2D2F4158D0453E00C7C176978D3F41D69C45DB cert=3c0SwxpOisbohNxEc4tb875RVW8eOu1opRTVXJhafaKA/PNNtI7ElQIVOVZg1AdL5bxGCw iat-mode=0
Bridge obfs4 52.15.78.72:9443 02069A3C5362476936B62BA6F5ACC41ABD573A9B cert=ijYG/OKc7kqu2YzKNFfeXN7/BG2BOgfEP2KyYEiGDQthnHbsOiTWHeIG0WJVW+BckzDgKw iat-mode=0
Bridge obfs4 13.58.29.242:9443 0C58939A77DA6B6B29D4B5236A75865659607AE0 cert=OylWIEHb/ezpq1zWxW0sgKRn+9ARH2eOcQOZ8/Gew+4l+oKOhQ2jUX/Y+FSl61JorXZUWA iat-mode=0
Bridge obfs4 45.33.37.112:9443 60A609BB4ABE8D46E634AE81ED29ADAB7776B399 cert=t5v19WmNv5Sc2YPNr8RQids365W7MY8zJwQVkOxBjUMFomMWARDzsbYpcWLLcw0J9Gm+BQ iat-mode=0
@@ -22,6 +22,7 @@ import org.briarproject.bramble.api.sync.Message;
import org.briarproject.bramble.api.sync.MessageFactory;
import org.briarproject.bramble.api.sync.MessageId;
import org.briarproject.bramble.test.BrambleTestCase;
import org.briarproject.bramble.test.DbExpectations;
import org.briarproject.bramble.util.StringUtils;
import org.jmock.Expectations;
import org.jmock.Mockery;
@@ -85,14 +86,11 @@ public class ClientHelperImplTest extends BrambleTestCase {
boolean shared = new Random().nextBoolean();
Transaction txn = new Transaction(null, false);
context.checking(new Expectations() {{
oneOf(db).startTransaction(false);
will(returnValue(txn));
context.checking(new DbExpectations() {{
oneOf(db).transaction(with(false), withDbRunnable(txn));
oneOf(metadataEncoder).encode(dictionary);
will(returnValue(metadata));
oneOf(db).addLocalMessage(txn, message, metadata, shared);
oneOf(db).commitTransaction(txn);
oneOf(db).endTransaction(txn);
}});
clientHelper.addLocalMessage(message, dictionary, shared);
@@ -116,13 +114,10 @@ public class ClientHelperImplTest extends BrambleTestCase {
Transaction txn = new Transaction(null, true);
expectToList(true);
context.checking(new Expectations() {{
oneOf(db).startTransaction(true);
will(returnValue(txn));
context.checking(new DbExpectations() {{
oneOf(db).transactionWithResult(with(true), withDbCallable(txn));
oneOf(db).getMessage(txn, messageId);
will(returnValue(message));
oneOf(db).commitTransaction(txn);
oneOf(db).endTransaction(txn);
}});
clientHelper.getMessageAsList(messageId);
@@ -133,15 +128,12 @@ public class ClientHelperImplTest extends BrambleTestCase {
public void testGetGroupMetadataAsDictionary() throws Exception {
Transaction txn = new Transaction(null, true);
context.checking(new Expectations() {{
oneOf(db).startTransaction(true);
will(returnValue(txn));
context.checking(new DbExpectations() {{
oneOf(db).transactionWithResult(with(true), withDbCallable(txn));
oneOf(db).getGroupMetadata(txn, groupId);
will(returnValue(metadata));
oneOf(metadataParser).parse(metadata);
will(returnValue(dictionary));
oneOf(db).commitTransaction(txn);
oneOf(db).endTransaction(txn);
}});
assertEquals(dictionary,
@@ -153,15 +145,12 @@ public class ClientHelperImplTest extends BrambleTestCase {
public void testGetMessageMetadataAsDictionary() throws Exception {
Transaction txn = new Transaction(null, true);
context.checking(new Expectations() {{
oneOf(db).startTransaction(true);
will(returnValue(txn));
context.checking(new DbExpectations() {{
oneOf(db).transactionWithResult(with(true), withDbCallable(txn));
oneOf(db).getMessageMetadata(txn, messageId);
will(returnValue(metadata));
oneOf(metadataParser).parse(metadata);
will(returnValue(dictionary));
oneOf(db).commitTransaction(txn);
oneOf(db).endTransaction(txn);
}});
assertEquals(dictionary,
@@ -175,15 +164,12 @@ public class ClientHelperImplTest extends BrambleTestCase {
map.put(messageId, dictionary);
Transaction txn = new Transaction(null, true);
context.checking(new Expectations() {{
oneOf(db).startTransaction(true);
will(returnValue(txn));
context.checking(new DbExpectations() {{
oneOf(db).transactionWithResult(with(true), withDbCallable(txn));
oneOf(db).getMessageMetadata(txn, groupId);
will(returnValue(Collections.singletonMap(messageId, metadata)));
oneOf(metadataParser).parse(metadata);
will(returnValue(dictionary));
oneOf(db).commitTransaction(txn);
oneOf(db).endTransaction(txn);
}});
assertEquals(map, clientHelper.getMessageMetadataAsDictionary(groupId));
@@ -200,17 +186,14 @@ public class ClientHelperImplTest extends BrambleTestCase {
queryMetadata.put("query", getRandomBytes(42));
Transaction txn = new Transaction(null, true);
context.checking(new Expectations() {{
oneOf(db).startTransaction(true);
will(returnValue(txn));
context.checking(new DbExpectations() {{
oneOf(db).transactionWithResult(with(true), withDbCallable(txn));
oneOf(metadataEncoder).encode(query);
will(returnValue(queryMetadata));
oneOf(db).getMessageMetadata(txn, groupId, queryMetadata);
will(returnValue(Collections.singletonMap(messageId, metadata)));
oneOf(metadataParser).parse(metadata);
will(returnValue(dictionary));
oneOf(db).commitTransaction(txn);
oneOf(db).endTransaction(txn);
}});
assertEquals(map,
@@ -222,14 +205,11 @@ public class ClientHelperImplTest extends BrambleTestCase {
public void testMergeGroupMetadata() throws Exception {
Transaction txn = new Transaction(null, false);
context.checking(new Expectations() {{
oneOf(db).startTransaction(false);
will(returnValue(txn));
context.checking(new DbExpectations() {{
oneOf(db).transaction(with(false), withDbRunnable(txn));
oneOf(metadataEncoder).encode(dictionary);
will(returnValue(metadata));
oneOf(db).mergeGroupMetadata(txn, groupId, metadata);
oneOf(db).commitTransaction(txn);
oneOf(db).endTransaction(txn);
}});
clientHelper.mergeGroupMetadata(groupId, dictionary);
@@ -240,14 +220,11 @@ public class ClientHelperImplTest extends BrambleTestCase {
public void testMergeMessageMetadata() throws Exception {
Transaction txn = new Transaction(null, false);
context.checking(new Expectations() {{
oneOf(db).startTransaction(false);
will(returnValue(txn));
context.checking(new DbExpectations() {{
oneOf(db).transaction(with(false), withDbRunnable(txn));
oneOf(metadataEncoder).encode(dictionary);
will(returnValue(metadata));
oneOf(db).mergeMessageMetadata(txn, messageId, metadata);
oneOf(db).commitTransaction(txn);
oneOf(db).endTransaction(txn);
}});
clientHelper.mergeMessageMetadata(messageId, dictionary);
@@ -69,17 +69,14 @@ public class ContactManagerImplTest extends BrambleMockTestCase {
boolean alice = new Random().nextBoolean();
Transaction txn = new Transaction(null, false);
context.checking(new Expectations() {{
oneOf(db).startTransaction(false);
will(returnValue(txn));
context.checking(new DbExpectations() {{
oneOf(db).transactionWithResult(with(false), withDbCallable(txn));
oneOf(db).addContact(txn, remote, local, verified, active);
will(returnValue(contactId));
oneOf(keyManager).addContact(txn, contactId, master, timestamp,
alice, active);
oneOf(db).getContact(txn, contactId);
will(returnValue(contact));
oneOf(db).commitTransaction(txn);
oneOf(db).endTransaction(txn);
}});
assertEquals(contactId, contactManager.addContact(remote, local,
@@ -89,13 +86,10 @@ public class ContactManagerImplTest extends BrambleMockTestCase {
@Test
public void testGetContact() throws Exception {
Transaction txn = new Transaction(null, true);
context.checking(new Expectations() {{
oneOf(db).startTransaction(true);
will(returnValue(txn));
context.checking(new DbExpectations() {{
oneOf(db).transactionWithResult(with(true), withDbCallable(txn));
oneOf(db).getContact(txn, contactId);
will(returnValue(contact));
oneOf(db).commitTransaction(txn);
oneOf(db).endTransaction(txn);
}});
assertEquals(contact, contactManager.getContact(contactId));
@@ -105,13 +99,10 @@ public class ContactManagerImplTest extends BrambleMockTestCase {
public void testGetContactByAuthor() throws Exception {
Transaction txn = new Transaction(null, true);
Collection<Contact> contacts = Collections.singleton(contact);
context.checking(new Expectations() {{
oneOf(db).startTransaction(true);
will(returnValue(txn));
context.checking(new DbExpectations() {{
oneOf(db).transactionWithResult(with(true), withDbCallable(txn));
oneOf(db).getContactsByAuthorId(txn, remote.getId());
will(returnValue(contacts));
oneOf(db).commitTransaction(txn);
oneOf(db).endTransaction(txn);
}});
assertEquals(contact, contactManager.getContact(remote.getId(), local));
@@ -120,12 +111,10 @@ public class ContactManagerImplTest extends BrambleMockTestCase {
@Test(expected = NoSuchContactException.class)
public void testGetContactByUnknownAuthor() throws Exception {
Transaction txn = new Transaction(null, true);
context.checking(new Expectations() {{
oneOf(db).startTransaction(true);
will(returnValue(txn));
context.checking(new DbExpectations() {{
oneOf(db).transactionWithResult(with(true), withDbCallable(txn));
oneOf(db).getContactsByAuthorId(txn, remote.getId());
will(returnValue(emptyList()));
oneOf(db).endTransaction(txn);
}});
contactManager.getContact(remote.getId(), local);
@@ -135,31 +124,26 @@ public class ContactManagerImplTest extends BrambleMockTestCase {
public void testGetContactByUnknownLocalAuthor() throws Exception {
Transaction txn = new Transaction(null, true);
Collection<Contact> contacts = Collections.singleton(contact);
context.checking(new Expectations() {{
oneOf(db).startTransaction(true);
will(returnValue(txn));
context.checking(new DbExpectations() {{
oneOf(db).transactionWithResult(with(true), withDbCallable(txn));
oneOf(db).getContactsByAuthorId(txn, remote.getId());
will(returnValue(contacts));
oneOf(db).endTransaction(txn);
}});
contactManager.getContact(remote.getId(), new AuthorId(getRandomId()));
}
@Test
public void testActiveContacts() throws Exception {
public void testGetActiveContacts() throws Exception {
Collection<Contact> activeContacts = Collections.singletonList(contact);
Collection<Contact> contacts = new ArrayList<>(activeContacts);
contacts.add(new Contact(new ContactId(3), remote, local, alias, true,
false));
Transaction txn = new Transaction(null, true);
context.checking(new Expectations() {{
oneOf(db).startTransaction(true);
will(returnValue(txn));
context.checking(new DbExpectations() {{
oneOf(db).transactionWithResult(with(true), withDbCallable(txn));
oneOf(db).getContacts(txn);
will(returnValue(contacts));
oneOf(db).commitTransaction(txn);
oneOf(db).endTransaction(txn);
}});
assertEquals(activeContacts, contactManager.getActiveContacts());
@@ -168,14 +152,11 @@ public class ContactManagerImplTest extends BrambleMockTestCase {
@Test
public void testRemoveContact() throws Exception {
Transaction txn = new Transaction(null, false);
context.checking(new Expectations() {{
oneOf(db).startTransaction(false);
will(returnValue(txn));
context.checking(new DbExpectations() {{
oneOf(db).transaction(with(false), withDbRunnable(txn));
oneOf(db).getContact(txn, contactId);
will(returnValue(contact));
oneOf(db).removeContact(txn, contactId);
oneOf(db).commitTransaction(txn);
oneOf(db).endTransaction(txn);
}});
contactManager.removeContact(contactId);
@@ -195,7 +176,7 @@ public class ContactManagerImplTest extends BrambleMockTestCase {
public void testSetContactAlias() throws Exception {
Transaction txn = new Transaction(null, false);
context.checking(new DbExpectations() {{
oneOf(db).transaction(with(equal(false)), withDbRunnable(txn));
oneOf(db).transaction(with(false), withDbRunnable(txn));
oneOf(db).setContactAlias(txn, contactId, alias);
}});
@@ -204,35 +185,32 @@ public class ContactManagerImplTest extends BrambleMockTestCase {
@Test(expected = IllegalArgumentException.class)
public void testSetContactAliasTooLong() throws Exception {
contactManager.setContactAlias(contactId,
Transaction txn = new Transaction(null, false);
contactManager.setContactAlias(txn, contactId,
getRandomString(MAX_AUTHOR_NAME_LENGTH + 1));
}
@Test
public void testContactExists() throws Exception {
Transaction txn = new Transaction(null, true);
context.checking(new Expectations() {{
oneOf(db).startTransaction(true);
will(returnValue(txn));
context.checking(new DbExpectations() {{
oneOf(db).transactionWithResult(with(true), withDbCallable(txn));
oneOf(db).containsContact(txn, remote.getId(), local);
will(returnValue(true));
oneOf(db).commitTransaction(txn);
oneOf(db).endTransaction(txn);
}});
assertTrue(contactManager.contactExists(remote.getId(), local));
}
@Test
public void testGetAuthorStatus() throws Exception {
public void testGetAuthorInfo() throws Exception {
Transaction txn = new Transaction(null, true);
Collection<Contact> contacts = singletonList(
new Contact(new ContactId(1), remote, localAuthor.getId(),
alias, false, true));
context.checking(new DbExpectations() {{
oneOf(db).transactionWithResult(with(equal(true)),
withDbCallable(txn));
oneOf(db).transactionWithResult(with(true), withDbCallable(txn));
oneOf(identityManager).getLocalAuthor(txn);
will(returnValue(localAuthor));
oneOf(db).getContactsByAuthorId(txn, remote.getId());
@@ -245,7 +223,7 @@ public class ContactManagerImplTest extends BrambleMockTestCase {
}
@Test
public void testGetAuthorStatusTransaction() throws DbException {
public void testGetAuthorInfoTransaction() throws DbException {
Transaction txn = new Transaction(null, true);
// check unknown author
@@ -264,7 +242,7 @@ public class ContactManagerImplTest extends BrambleMockTestCase {
Collection<Contact> contacts = singletonList(
new Contact(new ContactId(1), remote, localAuthor.getId(),
alias, false, true));
checkAuthorStatusContext(txn, remote.getId(), contacts);
checkAuthorInfoContext(txn, remote.getId(), contacts);
authorInfo = contactManager.getAuthorInfo(txn, remote.getId());
assertEquals(UNVERIFIED, authorInfo.getStatus());
assertEquals(alias, contact.getAlias());
@@ -272,7 +250,7 @@ public class ContactManagerImplTest extends BrambleMockTestCase {
// check verified contact
contacts = singletonList(new Contact(new ContactId(1), remote,
localAuthor.getId(), alias, true, true));
checkAuthorStatusContext(txn, remote.getId(), contacts);
checkAuthorInfoContext(txn, remote.getId(), contacts);
authorInfo = contactManager.getAuthorInfo(txn, remote.getId());
assertEquals(VERIFIED, authorInfo.getStatus());
assertEquals(alias, contact.getAlias());
@@ -288,7 +266,7 @@ public class ContactManagerImplTest extends BrambleMockTestCase {
assertNull(authorInfo.getAlias());
}
private void checkAuthorStatusContext(Transaction txn, AuthorId authorId,
private void checkAuthorInfoContext(Transaction txn, AuthorId authorId,
Collection<Contact> contacts) throws DbException {
context.checking(new Expectations() {{
oneOf(identityManager).getLocalAuthor(txn);
@@ -0,0 +1,41 @@
package org.briarproject.bramble.data;
import org.briarproject.bramble.test.BrambleTestCase;
import org.junit.Before;
import org.junit.Test;
import java.io.ByteArrayInputStream;
import java.util.Random;
import static org.briarproject.bramble.api.data.BdfReader.DEFAULT_MAX_BUFFER_SIZE;
import static org.briarproject.bramble.api.data.BdfReader.DEFAULT_NESTED_LIMIT;
import static org.briarproject.bramble.test.TestUtils.isOptionalTestEnabled;
import static org.junit.Assert.assertTrue;
import static org.junit.Assume.assumeTrue;
public class BdfReaderImplFuzzingTest extends BrambleTestCase {
@Before
public void setUp() {
assumeTrue(isOptionalTestEnabled(BdfReaderImplFuzzingTest.class));
}
@Test
public void testStringFuzzing() throws Exception {
Random random = new Random();
byte[] buf = new byte[22];
ByteArrayInputStream in = new ByteArrayInputStream(buf);
for (int i = 0; i < 100_000_000; i++) {
random.nextBytes(buf);
buf[0] = 0x41; // String with 1-byte length
buf[1] = 0x14; // Length 20 bytes
in.reset();
BdfReaderImpl r = new BdfReaderImpl(in, DEFAULT_NESTED_LIMIT,
DEFAULT_MAX_BUFFER_SIZE);
int length = r.readString().length();
assertTrue(length >= 0);
assertTrue(length <= 20);
assertTrue(r.eof());
}
}
}
File diff suppressed because it is too large Load Diff
@@ -11,7 +11,7 @@ import org.briarproject.bramble.api.sync.Group;
import org.briarproject.bramble.api.sync.GroupId;
import org.briarproject.bramble.api.sync.Message;
import org.briarproject.bramble.api.sync.MessageId;
import org.briarproject.bramble.api.sync.ValidationManager.State;
import org.briarproject.bramble.api.sync.validation.MessageState;
import org.briarproject.bramble.test.BrambleTestCase;
import org.briarproject.bramble.test.UTest;
import org.junit.After;
@@ -33,7 +33,7 @@ import java.util.logging.Logger;
import static java.util.logging.Level.OFF;
import static org.briarproject.bramble.api.sync.SyncConstants.MAX_MESSAGE_IDS;
import static org.briarproject.bramble.api.sync.ValidationManager.State.DELIVERED;
import static org.briarproject.bramble.api.sync.validation.MessageState.DELIVERED;
import static org.briarproject.bramble.test.TestUtils.deleteTestDirectory;
import static org.briarproject.bramble.test.TestUtils.getAuthor;
import static org.briarproject.bramble.test.TestUtils.getGroup;
@@ -565,7 +565,8 @@ public abstract class DatabasePerformanceTest extends BrambleTestCase {
for (int k = 0; k < MESSAGES_PER_GROUP; k++) {
Message m = getMessage(g.getId());
messages.add(m);
State state = State.fromValue(random.nextInt(4));
MessageState state =
MessageState.fromValue(random.nextInt(4));
boolean shared = random.nextBoolean();
ContactId sender = random.nextBoolean() ? c : null;
db.addMessage(txn, m, state, shared, sender);
@@ -18,7 +18,7 @@ import org.briarproject.bramble.api.sync.Message;
import org.briarproject.bramble.api.sync.MessageFactory;
import org.briarproject.bramble.api.sync.MessageId;
import org.briarproject.bramble.api.sync.MessageStatus;
import org.briarproject.bramble.api.sync.ValidationManager.State;
import org.briarproject.bramble.api.sync.validation.MessageState;
import org.briarproject.bramble.api.system.Clock;
import org.briarproject.bramble.api.transport.IncomingKeys;
import org.briarproject.bramble.api.transport.KeySet;
@@ -58,10 +58,10 @@ import static org.briarproject.bramble.api.sync.Group.Visibility.INVISIBLE;
import static org.briarproject.bramble.api.sync.Group.Visibility.SHARED;
import static org.briarproject.bramble.api.sync.Group.Visibility.VISIBLE;
import static org.briarproject.bramble.api.sync.SyncConstants.MAX_MESSAGE_BODY_LENGTH;
import static org.briarproject.bramble.api.sync.ValidationManager.State.DELIVERED;
import static org.briarproject.bramble.api.sync.ValidationManager.State.INVALID;
import static org.briarproject.bramble.api.sync.ValidationManager.State.PENDING;
import static org.briarproject.bramble.api.sync.ValidationManager.State.UNKNOWN;
import static org.briarproject.bramble.api.sync.validation.MessageState.DELIVERED;
import static org.briarproject.bramble.api.sync.validation.MessageState.INVALID;
import static org.briarproject.bramble.api.sync.validation.MessageState.PENDING;
import static org.briarproject.bramble.api.sync.validation.MessageState.UNKNOWN;
import static org.briarproject.bramble.db.DatabaseConstants.DB_SETTINGS_NAMESPACE;
import static org.briarproject.bramble.db.DatabaseConstants.LAST_COMPACTED_KEY;
import static org.briarproject.bramble.db.DatabaseConstants.MAX_COMPACTION_INTERVAL_MS;
@@ -1309,7 +1309,7 @@ public abstract class JdbcDatabaseTest extends BrambleTestCase {
db.addMessageDependency(txn, message1, messageId3, PENDING);
db.addMessageDependency(txn, message2, messageId4, INVALID);
Map<MessageId, State> dependencies;
Map<MessageId, MessageState> dependencies;
// Retrieve dependencies for root
dependencies = db.getMessageDependencies(txn, messageId);
@@ -1333,7 +1333,7 @@ public abstract class JdbcDatabaseTest extends BrambleTestCase {
dependencies = db.getMessageDependencies(txn, messageId4);
assertEquals(0, dependencies.size());
Map<MessageId, State> dependents;
Map<MessageId, MessageState> dependents;
// Root message does not have dependents
dependents = db.getMessageDependents(txn, messageId);
@@ -1408,7 +1408,7 @@ public abstract class JdbcDatabaseTest extends BrambleTestCase {
db.addMessageDependency(txn, message, messageId3, PENDING);
// Retrieve the dependencies for the root
Map<MessageId, State> dependencies;
Map<MessageId, MessageState> dependencies;
dependencies = db.getMessageDependencies(txn, messageId);
// The cross-group dependency should have state UNKNOWN
@@ -1421,7 +1421,7 @@ public abstract class JdbcDatabaseTest extends BrambleTestCase {
assertEquals(DELIVERED, dependencies.get(messageId3));
// Retrieve the dependents for the message in the second group
Map<MessageId, State> dependents;
Map<MessageId, MessageState> dependents;
dependents = db.getMessageDependents(txn, messageId1);
// The cross-group dependent should be excluded
@@ -11,6 +11,7 @@ import org.briarproject.bramble.api.identity.AuthorFactory;
import org.briarproject.bramble.api.identity.IdentityManager;
import org.briarproject.bramble.api.identity.LocalAuthor;
import org.briarproject.bramble.test.BrambleMockTestCase;
import org.briarproject.bramble.test.DbExpectations;
import org.jmock.Expectations;
import org.junit.Before;
import org.junit.Test;
@@ -64,13 +65,10 @@ public class IdentityManagerImplTest extends BrambleMockTestCase {
}
@Test
public void testRegisterAndStoreLocalAuthor() throws DbException {
context.checking(new Expectations() {{
oneOf(db).startTransaction(false);
will(returnValue(txn));
public void testRegisterAndStoreLocalAuthor() throws Exception {
context.checking(new DbExpectations() {{
oneOf(db).transaction(with(false), withDbRunnable(txn));
oneOf(db).addLocalAuthor(txn, localAuthor);
oneOf(db).commitTransaction(txn);
oneOf(db).endTransaction(txn);
}});
identityManager.registerLocalAuthor(localAuthor);
@@ -79,14 +77,11 @@ public class IdentityManagerImplTest extends BrambleMockTestCase {
}
@Test
public void testGetLocalAuthor() throws DbException {
context.checking(new Expectations() {{
oneOf(db).startTransaction(true);
will(returnValue(txn));
public void testGetLocalAuthor() throws Exception {
context.checking(new DbExpectations() {{
oneOf(db).transactionWithResult(with(true), withDbCallable(txn));
oneOf(db).getLocalAuthors(txn);
will(returnValue(localAuthors));
oneOf(db).commitTransaction(txn);
oneOf(db).endTransaction(txn);
}});
assertEquals(localAuthor, identityManager.getLocalAuthor());
}
@@ -21,16 +21,18 @@ import org.briarproject.bramble.api.sync.MessageId;
import org.briarproject.bramble.api.system.Clock;
import org.briarproject.bramble.api.versioning.ClientVersioningManager;
import org.briarproject.bramble.test.BrambleMockTestCase;
import org.briarproject.bramble.test.DbExpectations;
import org.jmock.Expectations;
import org.junit.Test;
import java.util.Arrays;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import static java.util.Arrays.asList;
import static java.util.Collections.singletonList;
import static java.util.Collections.singletonMap;
import static org.briarproject.bramble.api.properties.TransportPropertyManager.CLIENT_ID;
import static org.briarproject.bramble.api.properties.TransportPropertyManager.MAJOR_VERSION;
import static org.briarproject.bramble.api.sync.Group.Visibility.SHARED;
@@ -351,14 +353,11 @@ public class TransportPropertyManagerImplTest extends BrambleMockTestCase {
new BdfEntry("local", true)
));
context.checking(new Expectations() {{
oneOf(db).startTransaction(true);
will(returnValue(txn));
context.checking(new DbExpectations() {{
oneOf(db).transactionWithResult(with(true), withDbCallable(txn));
oneOf(clientHelper).getMessageMetadataAsDictionary(txn,
localGroup.getId());
will(returnValue(messageMetadata));
oneOf(db).commitTransaction(txn);
oneOf(db).endTransaction(txn);
}});
TransportPropertyManagerImpl t = createInstance();
@@ -386,9 +385,8 @@ public class TransportPropertyManagerImplTest extends BrambleMockTestCase {
));
BdfList fooUpdate = BdfList.of("foo", 1, fooPropertiesDict);
context.checking(new Expectations() {{
oneOf(db).startTransaction(true);
will(returnValue(txn));
context.checking(new DbExpectations() {{
oneOf(db).transactionWithResult(with(true), withDbCallable(txn));
oneOf(clientHelper).getMessageMetadataAsDictionary(txn,
localGroup.getId());
will(returnValue(messageMetadata));
@@ -397,8 +395,6 @@ public class TransportPropertyManagerImplTest extends BrambleMockTestCase {
oneOf(clientHelper).parseAndValidateTransportProperties(
fooPropertiesDict);
will(returnValue(fooProperties));
oneOf(db).commitTransaction(txn);
oneOf(db).endTransaction(txn);
}});
TransportPropertyManagerImpl t = createInstance();
@@ -413,8 +409,7 @@ public class TransportPropertyManagerImplTest extends BrambleMockTestCase {
Contact contact1 = getContact(false);
Contact contact2 = getContact(true);
Contact contact3 = getContact(true);
List<Contact> contacts =
Arrays.asList(contact1, contact2, contact3);
List<Contact> contacts = asList(contact1, contact2, contact3);
Group contactGroup2 = getGroup(CLIENT_ID, MAJOR_VERSION);
Group contactGroup3 = getGroup(CLIENT_ID, MAJOR_VERSION);
Map<MessageId, BdfDictionary> messageMetadata3 =
@@ -442,9 +437,8 @@ public class TransportPropertyManagerImplTest extends BrambleMockTestCase {
));
BdfList fooUpdate = BdfList.of("foo", 1, fooPropertiesDict);
context.checking(new Expectations() {{
oneOf(db).startTransaction(true);
will(returnValue(txn));
context.checking(new DbExpectations() {{
oneOf(db).transactionWithResult(with(true), withDbCallable(txn));
oneOf(db).getContacts(txn);
will(returnValue(contacts));
// First contact: skipped because not active
@@ -467,8 +461,6 @@ public class TransportPropertyManagerImplTest extends BrambleMockTestCase {
oneOf(clientHelper).parseAndValidateTransportProperties(
fooPropertiesDict);
will(returnValue(fooProperties));
oneOf(db).commitTransaction(txn);
oneOf(db).endTransaction(txn);
}});
TransportPropertyManagerImpl t = createInstance();
@@ -485,17 +477,16 @@ public class TransportPropertyManagerImplTest extends BrambleMockTestCase {
throws Exception {
Transaction txn = new Transaction(null, false);
MessageId updateId = new MessageId(getRandomId());
Map<MessageId, BdfDictionary> messageMetadata =
Collections.singletonMap(updateId, BdfDictionary.of(
Map<MessageId, BdfDictionary> messageMetadata = singletonMap(updateId,
BdfDictionary.of(
new BdfEntry("transportId", "foo"),
new BdfEntry("version", 1),
new BdfEntry("local", true)
));
BdfList update = BdfList.of("foo", 1, fooPropertiesDict);
context.checking(new Expectations() {{
oneOf(db).startTransaction(false);
will(returnValue(txn));
context.checking(new DbExpectations() {{
oneOf(db).transaction(with(false), withDbRunnable(txn));
// Merge the new properties with the existing properties
oneOf(clientHelper).getMessageMetadataAsDictionary(txn,
localGroup.getId());
@@ -506,8 +497,6 @@ public class TransportPropertyManagerImplTest extends BrambleMockTestCase {
fooPropertiesDict);
will(returnValue(fooProperties));
// Properties are unchanged so we're done
oneOf(db).commitTransaction(txn);
oneOf(db).endTransaction(txn);
}});
TransportPropertyManagerImpl t = createInstance();
@@ -520,9 +509,8 @@ public class TransportPropertyManagerImplTest extends BrambleMockTestCase {
Contact contact = getContact(true);
Group contactGroup = getGroup(CLIENT_ID, MAJOR_VERSION);
context.checking(new Expectations() {{
oneOf(db).startTransaction(false);
will(returnValue(txn));
context.checking(new DbExpectations() {{
oneOf(db).transaction(with(false), withDbRunnable(txn));
// There are no existing properties to merge with
oneOf(clientHelper).getMessageMetadataAsDictionary(txn,
localGroup.getId());
@@ -541,8 +529,6 @@ public class TransportPropertyManagerImplTest extends BrambleMockTestCase {
will(returnValue(Collections.emptyMap()));
expectStoreMessage(txn, contactGroup.getId(), "foo",
fooPropertiesDict, 1, true, true);
oneOf(db).commitTransaction(txn);
oneOf(db).endTransaction(txn);
}});
TransportPropertyManagerImpl t = createInstance();
@@ -561,10 +547,10 @@ public class TransportPropertyManagerImplTest extends BrambleMockTestCase {
);
MessageId localGroupUpdateId = new MessageId(getRandomId());
Map<MessageId, BdfDictionary> localGroupMessageMetadata =
Collections.singletonMap(localGroupUpdateId, oldMetadata);
singletonMap(localGroupUpdateId, oldMetadata);
MessageId contactGroupUpdateId = new MessageId(getRandomId());
Map<MessageId, BdfDictionary> contactGroupMessageMetadata =
Collections.singletonMap(contactGroupUpdateId, oldMetadata);
singletonMap(contactGroupUpdateId, oldMetadata);
TransportProperties oldProperties = new TransportProperties();
oldProperties.put("fooKey1", "oldFooValue1");
BdfDictionary oldPropertiesDict = BdfDictionary.of(
@@ -572,9 +558,8 @@ public class TransportPropertyManagerImplTest extends BrambleMockTestCase {
);
BdfList oldUpdate = BdfList.of("foo", 1, oldPropertiesDict);
context.checking(new Expectations() {{
oneOf(db).startTransaction(false);
will(returnValue(txn));
context.checking(new DbExpectations() {{
oneOf(db).transaction(with(false), withDbRunnable(txn));
// Merge the new properties with the existing properties
oneOf(clientHelper).getMessageMetadataAsDictionary(txn,
localGroup.getId());
@@ -602,8 +587,6 @@ public class TransportPropertyManagerImplTest extends BrambleMockTestCase {
fooPropertiesDict, 2, true, true);
// Delete the previous update
oneOf(db).removeMessage(txn, contactGroupUpdateId);
oneOf(db).commitTransaction(txn);
oneOf(db).endTransaction(txn);
}});
TransportPropertyManagerImpl t = createInstance();
@@ -11,8 +11,8 @@ import org.briarproject.bramble.api.sync.MessageId;
import org.briarproject.bramble.api.sync.SyncRecordWriter;
import org.briarproject.bramble.api.transport.StreamWriter;
import org.briarproject.bramble.test.BrambleMockTestCase;
import org.briarproject.bramble.test.DbExpectations;
import org.briarproject.bramble.test.ImmediateExecutor;
import org.jmock.Expectations;
import org.junit.Test;
import java.util.concurrent.Executor;
@@ -45,24 +45,20 @@ public class SimplexOutgoingSessionTest extends BrambleMockTestCase {
Transaction noAckTxn = new Transaction(null, false);
Transaction noMsgTxn = new Transaction(null, false);
context.checking(new Expectations() {{
context.checking(new DbExpectations() {{
// Add listener
oneOf(eventBus).addListener(session);
// No acks to send
oneOf(db).startTransaction(false);
will(returnValue(noAckTxn));
oneOf(db).transactionWithNullableResult(with(false),
withNullableDbCallable(noAckTxn));
oneOf(db).generateAck(noAckTxn, contactId, MAX_MESSAGE_IDS);
will(returnValue(null));
oneOf(db).commitTransaction(noAckTxn);
oneOf(db).endTransaction(noAckTxn);
// No messages to send
oneOf(db).startTransaction(false);
will(returnValue(noMsgTxn));
oneOf(db).transactionWithNullableResult(with(false),
withNullableDbCallable(noMsgTxn));
oneOf(db).generateBatch(with(noMsgTxn), with(contactId),
with(any(int.class)), with(MAX_LATENCY));
will(returnValue(null));
oneOf(db).commitTransaction(noMsgTxn);
oneOf(db).endTransaction(noMsgTxn);
// Send the end of stream marker
oneOf(streamWriter).sendEndOfStream();
// Remove listener
@@ -83,41 +79,33 @@ public class SimplexOutgoingSessionTest extends BrambleMockTestCase {
Transaction msgTxn = new Transaction(null, false);
Transaction noMsgTxn = new Transaction(null, false);
context.checking(new Expectations() {{
context.checking(new DbExpectations() {{
// Add listener
oneOf(eventBus).addListener(session);
// One ack to send
oneOf(db).startTransaction(false);
will(returnValue(ackTxn));
oneOf(db).transactionWithNullableResult(with(false),
withNullableDbCallable(ackTxn));
oneOf(db).generateAck(ackTxn, contactId, MAX_MESSAGE_IDS);
will(returnValue(ack));
oneOf(db).commitTransaction(ackTxn);
oneOf(db).endTransaction(ackTxn);
oneOf(recordWriter).writeAck(ack);
// One message to send
oneOf(db).startTransaction(false);
will(returnValue(msgTxn));
oneOf(db).transactionWithNullableResult(with(false),
withNullableDbCallable(msgTxn));
oneOf(db).generateBatch(with(msgTxn), with(contactId),
with(any(int.class)), with(MAX_LATENCY));
will(returnValue(singletonList(message)));
oneOf(db).commitTransaction(msgTxn);
oneOf(db).endTransaction(msgTxn);
oneOf(recordWriter).writeMessage(message);
// No more acks
oneOf(db).startTransaction(false);
will(returnValue(noAckTxn));
oneOf(db).transactionWithNullableResult(with(false),
withNullableDbCallable(noAckTxn));
oneOf(db).generateAck(noAckTxn, contactId, MAX_MESSAGE_IDS);
will(returnValue(null));
oneOf(db).commitTransaction(noAckTxn);
oneOf(db).endTransaction(noAckTxn);
// No more messages
oneOf(db).startTransaction(false);
will(returnValue(noMsgTxn));
oneOf(db).transactionWithNullableResult(with(false),
withNullableDbCallable(noMsgTxn));
oneOf(db).generateBatch(with(noMsgTxn), with(contactId),
with(any(int.class)), with(MAX_LATENCY));
will(returnValue(null));
oneOf(db).commitTransaction(noMsgTxn);
oneOf(db).endTransaction(noMsgTxn);
// Send the end of stream marker
oneOf(streamWriter).sendEndOfStream();
// Remove listener
@@ -2,6 +2,7 @@ package org.briarproject.bramble.sync;
import org.briarproject.bramble.crypto.CryptoModule;
import org.briarproject.bramble.record.RecordModule;
import org.briarproject.bramble.sync.validation.ValidationModule;
import org.briarproject.bramble.system.SystemModule;
import org.briarproject.bramble.test.TestSecureRandomModule;
import org.briarproject.bramble.transport.TransportModule;
@@ -17,6 +18,7 @@ import dagger.Component;
RecordModule.class,
SyncModule.class,
SystemModule.class,
ValidationModule.class,
TransportModule.class
})
interface SyncIntegrationTestComponent {
@@ -1,4 +1,4 @@
package org.briarproject.bramble.sync;
package org.briarproject.bramble.sync.validation;
import org.briarproject.bramble.api.contact.ContactId;
import org.briarproject.bramble.api.db.DatabaseComponent;
@@ -13,29 +13,29 @@ import org.briarproject.bramble.api.sync.InvalidMessageException;
import org.briarproject.bramble.api.sync.Message;
import org.briarproject.bramble.api.sync.MessageContext;
import org.briarproject.bramble.api.sync.MessageId;
import org.briarproject.bramble.api.sync.ValidationManager.IncomingMessageHook;
import org.briarproject.bramble.api.sync.ValidationManager.MessageValidator;
import org.briarproject.bramble.api.sync.ValidationManager.State;
import org.briarproject.bramble.api.sync.event.MessageAddedEvent;
import org.briarproject.bramble.api.sync.validation.IncomingMessageHook;
import org.briarproject.bramble.api.sync.validation.MessageState;
import org.briarproject.bramble.api.sync.validation.MessageValidator;
import org.briarproject.bramble.test.BrambleMockTestCase;
import org.briarproject.bramble.test.DbExpectations;
import org.briarproject.bramble.test.ImmediateExecutor;
import org.jmock.Expectations;
import org.junit.Before;
import org.junit.Test;
import java.util.Arrays;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.concurrent.Executor;
import static java.util.Arrays.asList;
import static java.util.Collections.emptyList;
import static java.util.Collections.emptyMap;
import static java.util.Collections.singletonList;
import static java.util.Collections.singletonMap;
import static org.briarproject.bramble.api.sync.ValidationManager.State.DELIVERED;
import static org.briarproject.bramble.api.sync.ValidationManager.State.INVALID;
import static org.briarproject.bramble.api.sync.ValidationManager.State.PENDING;
import static org.briarproject.bramble.api.sync.ValidationManager.State.UNKNOWN;
import static org.briarproject.bramble.api.sync.validation.MessageState.DELIVERED;
import static org.briarproject.bramble.api.sync.validation.MessageState.INVALID;
import static org.briarproject.bramble.api.sync.validation.MessageState.PENDING;
import static org.briarproject.bramble.api.sync.validation.MessageState.UNKNOWN;
import static org.briarproject.bramble.test.TestUtils.getClientId;
import static org.briarproject.bramble.test.TestUtils.getGroup;
import static org.briarproject.bramble.test.TestUtils.getMessage;
@@ -83,28 +83,19 @@ public class ValidationManagerImplTest extends BrambleMockTestCase {
Transaction txn1 = new Transaction(null, true);
Transaction txn2 = new Transaction(null, true);
context.checking(new Expectations() {{
context.checking(new DbExpectations() {{
// validateOutstandingMessages()
oneOf(db).startTransaction(true);
will(returnValue(txn));
oneOf(db).transactionWithResult(with(true), withDbCallable(txn));
oneOf(db).getMessagesToValidate(txn);
will(returnValue(emptyList()));
oneOf(db).commitTransaction(txn);
oneOf(db).endTransaction(txn);
// deliverOutstandingMessages()
oneOf(db).startTransaction(true);
will(returnValue(txn1));
oneOf(db).transactionWithResult(with(true), withDbCallable(txn1));
oneOf(db).getPendingMessages(txn1);
will(returnValue(emptyList()));
oneOf(db).commitTransaction(txn1);
oneOf(db).endTransaction(txn1);
// shareOutstandingMessages()
oneOf(db).startTransaction(true);
will(returnValue(txn2));
oneOf(db).transactionWithResult(with(true), withDbCallable(txn2));
oneOf(db).getMessagesToShare(txn2);
will(returnValue(emptyList()));
oneOf(db).commitTransaction(txn2);
oneOf(db).endTransaction(txn2);
}});
vm.startService();
@@ -121,29 +112,22 @@ public class ValidationManagerImplTest extends BrambleMockTestCase {
Transaction txn5 = new Transaction(null, true);
Transaction txn6 = new Transaction(null, true);
context.checking(new Expectations() {{
context.checking(new DbExpectations() {{
// Get messages to validate
oneOf(db).startTransaction(true);
will(returnValue(txn));
oneOf(db).transactionWithResult(with(true), withDbCallable(txn));
oneOf(db).getMessagesToValidate(txn);
will(returnValue(Arrays.asList(messageId, messageId1)));
oneOf(db).commitTransaction(txn);
oneOf(db).endTransaction(txn);
will(returnValue(asList(messageId, messageId1)));
// Load the first raw message and group
oneOf(db).startTransaction(true);
will(returnValue(txn1));
oneOf(db).transactionWithResult(with(true), withDbCallable(txn1));
oneOf(db).getMessage(txn1, messageId);
will(returnValue(message));
oneOf(db).getGroup(txn1, groupId);
will(returnValue(group));
oneOf(db).commitTransaction(txn1);
oneOf(db).endTransaction(txn1);
// Validate the first message: valid
oneOf(validator).validateMessage(message, group);
will(returnValue(validResult));
// Store the validation result for the first message
oneOf(db).startTransaction(false);
will(returnValue(txn2));
oneOf(db).transaction(with(false), withDbRunnable(txn2));
oneOf(db).mergeMessageMetadata(txn2, messageId, metadata);
// Deliver the first message
oneOf(hook).incomingMessage(txn2, message, metadata);
@@ -152,23 +136,17 @@ public class ValidationManagerImplTest extends BrambleMockTestCase {
// Get any pending dependents
oneOf(db).getMessageDependents(txn2, messageId);
will(returnValue(emptyMap()));
oneOf(db).commitTransaction(txn2);
oneOf(db).endTransaction(txn2);
// Load the second raw message and group
oneOf(db).startTransaction(true);
will(returnValue(txn3));
oneOf(db).transactionWithResult(with(true), withDbCallable(txn3));
oneOf(db).getMessage(txn3, messageId1);
will(returnValue(message1));
oneOf(db).getGroup(txn3, groupId);
will(returnValue(group));
oneOf(db).commitTransaction(txn3);
oneOf(db).endTransaction(txn3);
// Validate the second message: invalid
oneOf(validator).validateMessage(message1, group);
will(throwException(new InvalidMessageException()));
// Store the validation result for the second message
oneOf(db).startTransaction(false);
will(returnValue(txn4));
oneOf(db).transaction(with(false), withDbRunnable(txn4));
oneOf(db).getMessageState(txn4, messageId1);
will(returnValue(UNKNOWN));
oneOf(db).setMessageState(txn4, messageId1, INVALID);
@@ -177,22 +155,14 @@ public class ValidationManagerImplTest extends BrambleMockTestCase {
// Recursively invalidate any dependents
oneOf(db).getMessageDependents(txn4, messageId1);
will(returnValue(emptyMap()));
oneOf(db).commitTransaction(txn4);
oneOf(db).endTransaction(txn4);
// Get pending messages to deliver
oneOf(db).startTransaction(true);
will(returnValue(txn5));
oneOf(db).transactionWithResult(with(true), withDbCallable(txn5));
oneOf(db).getPendingMessages(txn5);
will(returnValue(emptyList()));
oneOf(db).commitTransaction(txn5);
oneOf(db).endTransaction(txn5);
// Get messages to share
oneOf(db).startTransaction(true);
will(returnValue(txn6));
oneOf(db).transactionWithResult(with(true), withDbCallable(txn6));
oneOf(db).getMessagesToShare(txn6);
will(returnValue(emptyList()));
oneOf(db).commitTransaction(txn6);
oneOf(db).endTransaction(txn6);
}});
vm.startService();
@@ -206,24 +176,17 @@ public class ValidationManagerImplTest extends BrambleMockTestCase {
Transaction txn3 = new Transaction(null, false);
Transaction txn4 = new Transaction(null, true);
context.checking(new Expectations() {{
context.checking(new DbExpectations() {{
// Get messages to validate
oneOf(db).startTransaction(true);
will(returnValue(txn));
oneOf(db).transactionWithResult(with(true), withDbCallable(txn));
oneOf(db).getMessagesToValidate(txn);
will(returnValue(emptyList()));
oneOf(db).commitTransaction(txn);
oneOf(db).endTransaction(txn);
// Get pending messages to deliver
oneOf(db).startTransaction(true);
will(returnValue(txn1));
oneOf(db).transactionWithResult(with(true), withDbCallable(txn1));
oneOf(db).getPendingMessages(txn1);
will(returnValue(singletonList(messageId)));
oneOf(db).commitTransaction(txn1);
oneOf(db).endTransaction(txn1);
// Check whether the message is ready to deliver
oneOf(db).startTransaction(false);
will(returnValue(txn2));
oneOf(db).transaction(with(false), withDbRunnable(txn2));
oneOf(db).getMessageState(txn2, messageId);
will(returnValue(PENDING));
oneOf(db).getMessageDependencies(txn2, messageId);
@@ -242,11 +205,8 @@ public class ValidationManagerImplTest extends BrambleMockTestCase {
// Get any pending dependents
oneOf(db).getMessageDependents(txn2, messageId);
will(returnValue(singletonMap(messageId2, PENDING)));
oneOf(db).commitTransaction(txn2);
oneOf(db).endTransaction(txn2);
// Check whether the dependent is ready to deliver
oneOf(db).startTransaction(false);
will(returnValue(txn3));
oneOf(db).transaction(with(false), withDbRunnable(txn3));
oneOf(db).getMessageState(txn3, messageId2);
will(returnValue(PENDING));
oneOf(db).getMessageDependencies(txn3, messageId2);
@@ -265,16 +225,11 @@ public class ValidationManagerImplTest extends BrambleMockTestCase {
// Get any pending dependents
oneOf(db).getMessageDependents(txn3, messageId2);
will(returnValue(emptyMap()));
oneOf(db).commitTransaction(txn3);
oneOf(db).endTransaction(txn3);
// Get messages to share
oneOf(db).startTransaction(true);
will(returnValue(txn4));
oneOf(db).transactionWithResult(with(true), withDbCallable(txn4));
oneOf(db).getMessagesToShare(txn4);
will(returnValue(emptyList()));
oneOf(db).commitTransaction(txn4);
oneOf(db).endTransaction(txn4);
}});
vm.startService();
@@ -288,45 +243,30 @@ public class ValidationManagerImplTest extends BrambleMockTestCase {
Transaction txn3 = new Transaction(null, false);
Transaction txn4 = new Transaction(null, false);
context.checking(new Expectations() {{
context.checking(new DbExpectations() {{
// No messages to validate
oneOf(db).startTransaction(true);
will(returnValue(txn));
oneOf(db).transactionWithResult(with(true), withDbCallable(txn));
oneOf(db).getMessagesToValidate(txn);
will(returnValue(emptyList()));
oneOf(db).commitTransaction(txn);
oneOf(db).endTransaction(txn);
// No pending messages to deliver
oneOf(db).startTransaction(true);
will(returnValue(txn1));
oneOf(db).transactionWithResult(with(true), withDbCallable(txn1));
oneOf(db).getPendingMessages(txn1);
will(returnValue(emptyList()));
oneOf(db).commitTransaction(txn1);
oneOf(db).endTransaction(txn1);
// Get messages to share
oneOf(db).startTransaction(true);
will(returnValue(txn2));
oneOf(db).transactionWithResult(with(true), withDbCallable(txn2));
oneOf(db).getMessagesToShare(txn2);
will(returnValue(singletonList(messageId)));
oneOf(db).commitTransaction(txn2);
oneOf(db).endTransaction(txn2);
// Share message and get dependencies
oneOf(db).startTransaction(false);
will(returnValue(txn3));
oneOf(db).transaction(with(false), withDbRunnable(txn3));
oneOf(db).setMessageShared(txn3, messageId);
oneOf(db).getMessageDependencies(txn3, messageId);
will(returnValue(singletonMap(messageId2, DELIVERED)));
oneOf(db).commitTransaction(txn3);
oneOf(db).endTransaction(txn3);
// Share dependency
oneOf(db).startTransaction(false);
will(returnValue(txn4));
oneOf(db).transaction(with(false), withDbRunnable(txn4));
oneOf(db).setMessageShared(txn4, messageId2);
oneOf(db).getMessageDependencies(txn4, messageId2);
will(returnValue(emptyMap()));
oneOf(db).commitTransaction(txn4);
oneOf(db).endTransaction(txn4);
}});
vm.startService();
@@ -338,20 +278,16 @@ public class ValidationManagerImplTest extends BrambleMockTestCase {
Transaction txn1 = new Transaction(null, false);
Transaction txn2 = new Transaction(null, false);
context.checking(new Expectations() {{
context.checking(new DbExpectations() {{
// Load the group
oneOf(db).startTransaction(true);
will(returnValue(txn));
oneOf(db).transactionWithResult(with(true), withDbCallable(txn));
oneOf(db).getGroup(txn, groupId);
will(returnValue(group));
oneOf(db).commitTransaction(txn);
oneOf(db).endTransaction(txn);
// Validate the message: valid
oneOf(validator).validateMessage(message, group);
will(returnValue(validResultWithDependencies));
// Store the validation result
oneOf(db).startTransaction(false);
will(returnValue(txn1));
oneOf(db).transaction(with(false), withDbRunnable(txn1));
oneOf(db).addMessageDependencies(txn1, message,
validResultWithDependencies.getDependencies());
oneOf(db).getMessageDependencies(txn1, messageId);
@@ -366,16 +302,11 @@ public class ValidationManagerImplTest extends BrambleMockTestCase {
will(returnValue(emptyMap()));
// Share message
oneOf(db).setMessageShared(txn1, messageId);
oneOf(db).commitTransaction(txn1);
oneOf(db).endTransaction(txn1);
// Share dependencies
oneOf(db).startTransaction(false);
will(returnValue(txn2));
oneOf(db).transaction(with(false), withDbRunnable(txn2));
oneOf(db).setMessageShared(txn2, messageId1);
oneOf(db).getMessageDependencies(txn2, messageId1);
will(returnValue(emptyMap()));
oneOf(db).commitTransaction(txn2);
oneOf(db).endTransaction(txn2);
}});
vm.eventOccurred(new MessageAddedEvent(message, contactId));
@@ -391,36 +322,26 @@ public class ValidationManagerImplTest extends BrambleMockTestCase {
Transaction txn4 = new Transaction(null, true);
Transaction txn5 = new Transaction(null, true);
context.checking(new Expectations() {{
context.checking(new DbExpectations() {{
// Get messages to validate
oneOf(db).startTransaction(true);
will(returnValue(txn));
oneOf(db).transactionWithResult(with(true), withDbCallable(txn));
oneOf(db).getMessagesToValidate(txn);
will(returnValue(Arrays.asList(messageId, messageId1)));
oneOf(db).commitTransaction(txn);
oneOf(db).endTransaction(txn);
will(returnValue(asList(messageId, messageId1)));
// Load the first raw message - *gasp* it's gone!
oneOf(db).startTransaction(true);
will(returnValue(txn1));
oneOf(db).transactionWithResult(with(true), withDbCallable(txn1));
oneOf(db).getMessage(txn1, messageId);
will(throwException(new NoSuchMessageException()));
never(db).commitTransaction(txn1);
oneOf(db).endTransaction(txn1);
// Load the second raw message and group
oneOf(db).startTransaction(true);
will(returnValue(txn2));
oneOf(db).transactionWithResult(with(true), withDbCallable(txn2));
oneOf(db).getMessage(txn2, messageId1);
will(returnValue(message1));
oneOf(db).getGroup(txn2, groupId);
will(returnValue(group));
oneOf(db).commitTransaction(txn2);
oneOf(db).endTransaction(txn2);
// Validate the second message: invalid
oneOf(validator).validateMessage(message1, group);
will(throwException(new InvalidMessageException()));
// Invalidate the second message
oneOf(db).startTransaction(false);
will(returnValue(txn3));
oneOf(db).transaction(with(false), withDbRunnable(txn3));
oneOf(db).getMessageState(txn3, messageId1);
will(returnValue(UNKNOWN));
oneOf(db).setMessageState(txn3, messageId1, INVALID);
@@ -429,22 +350,14 @@ public class ValidationManagerImplTest extends BrambleMockTestCase {
// Recursively invalidate dependents
oneOf(db).getMessageDependents(txn3, messageId1);
will(returnValue(emptyMap()));
oneOf(db).commitTransaction(txn3);
oneOf(db).endTransaction(txn3);
// Get pending messages to deliver
oneOf(db).startTransaction(true);
will(returnValue(txn4));
oneOf(db).transactionWithResult(with(true), withDbCallable(txn4));
oneOf(db).getPendingMessages(txn4);
will(returnValue(emptyList()));
oneOf(db).commitTransaction(txn4);
oneOf(db).endTransaction(txn4);
// Get messages to share
oneOf(db).startTransaction(true);
will(returnValue(txn5));
oneOf(db).transactionWithResult(with(true), withDbCallable(txn5));
oneOf(db).getMessagesToShare(txn5);
will(returnValue(emptyList()));
oneOf(db).commitTransaction(txn5);
oneOf(db).endTransaction(txn5);
}});
vm.startService();
@@ -460,39 +373,29 @@ public class ValidationManagerImplTest extends BrambleMockTestCase {
Transaction txn4 = new Transaction(null, true);
Transaction txn5 = new Transaction(null, true);
context.checking(new Expectations() {{
context.checking(new DbExpectations() {{
// Get messages to validate
oneOf(db).startTransaction(true);
will(returnValue(txn));
oneOf(db).transactionWithResult(with(true), withDbCallable(txn));
oneOf(db).getMessagesToValidate(txn);
will(returnValue(Arrays.asList(messageId, messageId1)));
oneOf(db).commitTransaction(txn);
oneOf(db).endTransaction(txn);
will(returnValue(asList(messageId, messageId1)));
// Load the first raw message
oneOf(db).startTransaction(true);
will(returnValue(txn1));
oneOf(db).transactionWithResult(with(true), withDbCallable(txn1));
oneOf(db).getMessage(txn1, messageId);
will(returnValue(message));
// Load the group - *gasp* it's gone!
oneOf(db).getGroup(txn1, groupId);
will(throwException(new NoSuchGroupException()));
never(db).commitTransaction(txn1);
oneOf(db).endTransaction(txn1);
// Load the second raw message and group
oneOf(db).startTransaction(true);
will(returnValue(txn2));
oneOf(db).transactionWithResult(with(true), withDbCallable(txn2));
oneOf(db).getMessage(txn2, messageId1);
will(returnValue(message1));
oneOf(db).getGroup(txn2, groupId);
will(returnValue(group));
oneOf(db).commitTransaction(txn2);
oneOf(db).endTransaction(txn2);
// Validate the second message: invalid
oneOf(validator).validateMessage(message1, group);
will(throwException(new InvalidMessageException()));
// Store the validation result for the second message
oneOf(db).startTransaction(false);
will(returnValue(txn3));
oneOf(db).transaction(with(false), withDbRunnable(txn3));
oneOf(db).getMessageState(txn3, messageId1);
will(returnValue(UNKNOWN));
oneOf(db).setMessageState(txn3, messageId1, INVALID);
@@ -501,22 +404,14 @@ public class ValidationManagerImplTest extends BrambleMockTestCase {
// Recursively invalidate dependents
oneOf(db).getMessageDependents(txn3, messageId1);
will(returnValue(emptyMap()));
oneOf(db).commitTransaction(txn3);
oneOf(db).endTransaction(txn3);
// Get pending messages to deliver
oneOf(db).startTransaction(true);
will(returnValue(txn4));
oneOf(db).transactionWithResult(with(true), withDbCallable(txn4));
oneOf(db).getPendingMessages(txn4);
will(returnValue(emptyList()));
oneOf(db).commitTransaction(txn4);
oneOf(db).endTransaction(txn4);
// Get messages to share
oneOf(db).startTransaction(true);
will(returnValue(txn5));
oneOf(db).transactionWithResult(with(true), withDbCallable(txn5));
oneOf(db).getMessagesToShare(txn5);
will(returnValue(emptyList()));
oneOf(db).commitTransaction(txn5);
oneOf(db).endTransaction(txn5);
}});
vm.startService();
@@ -527,20 +422,16 @@ public class ValidationManagerImplTest extends BrambleMockTestCase {
Transaction txn = new Transaction(null, true);
Transaction txn1 = new Transaction(null, false);
context.checking(new Expectations() {{
context.checking(new DbExpectations() {{
// Load the group
oneOf(db).startTransaction(true);
will(returnValue(txn));
oneOf(db).transactionWithResult(with(true), withDbCallable(txn));
oneOf(db).getGroup(txn, groupId);
will(returnValue(group));
oneOf(db).commitTransaction(txn);
oneOf(db).endTransaction(txn);
// Validate the message: valid
oneOf(validator).validateMessage(message, group);
will(returnValue(validResult));
// Store the validation result
oneOf(db).startTransaction(false);
will(returnValue(txn1));
oneOf(db).transaction(with(false), withDbRunnable(txn1));
oneOf(db).mergeMessageMetadata(txn1, messageId, metadata);
// Deliver the message
oneOf(hook).incomingMessage(txn1, message, metadata);
@@ -549,8 +440,6 @@ public class ValidationManagerImplTest extends BrambleMockTestCase {
// Get any pending dependents
oneOf(db).getMessageDependents(txn1, messageId);
will(returnValue(emptyMap()));
oneOf(db).commitTransaction(txn1);
oneOf(db).endTransaction(txn1);
}});
vm.eventOccurred(new MessageAddedEvent(message, contactId));
@@ -567,28 +456,22 @@ public class ValidationManagerImplTest extends BrambleMockTestCase {
Transaction txn = new Transaction(null, true);
Transaction txn1 = new Transaction(null, false);
context.checking(new Expectations() {{
context.checking(new DbExpectations() {{
// Load the group
oneOf(db).startTransaction(true);
will(returnValue(txn));
oneOf(db).transactionWithResult(with(true), withDbCallable(txn));
oneOf(db).getGroup(txn, groupId);
will(returnValue(group));
oneOf(db).commitTransaction(txn);
oneOf(db).endTransaction(txn);
// Validate the message: valid
oneOf(validator).validateMessage(message, group);
will(returnValue(validResultWithDependencies));
// Store the validation result
oneOf(db).startTransaction(false);
will(returnValue(txn1));
oneOf(db).transaction(with(false), withDbRunnable(txn1));
oneOf(db).addMessageDependencies(txn1, message,
validResultWithDependencies.getDependencies());
oneOf(db).getMessageDependencies(txn1, messageId);
will(returnValue(singletonMap(messageId1, UNKNOWN)));
oneOf(db).mergeMessageMetadata(txn1, messageId, metadata);
oneOf(db).setMessageState(txn1, messageId, PENDING);
oneOf(db).commitTransaction(txn1);
oneOf(db).endTransaction(txn1);
}});
vm.eventOccurred(new MessageAddedEvent(message, contactId));
@@ -600,20 +483,16 @@ public class ValidationManagerImplTest extends BrambleMockTestCase {
Transaction txn = new Transaction(null, true);
Transaction txn1 = new Transaction(null, false);
context.checking(new Expectations() {{
context.checking(new DbExpectations() {{
// Load the group
oneOf(db).startTransaction(true);
will(returnValue(txn));
oneOf(db).transactionWithResult(with(true), withDbCallable(txn));
oneOf(db).getGroup(txn, groupId);
will(returnValue(group));
oneOf(db).commitTransaction(txn);
oneOf(db).endTransaction(txn);
// Validate the message: valid
oneOf(validator).validateMessage(message, group);
will(returnValue(validResultWithDependencies));
// Store the validation result
oneOf(db).startTransaction(false);
will(returnValue(txn1));
oneOf(db).transaction(with(false), withDbRunnable(txn1));
oneOf(db).addMessageDependencies(txn1, message,
validResultWithDependencies.getDependencies());
oneOf(db).getMessageDependencies(txn1, messageId);
@@ -626,8 +505,6 @@ public class ValidationManagerImplTest extends BrambleMockTestCase {
// Get any pending dependents
oneOf(db).getMessageDependents(txn1, messageId);
will(returnValue(emptyMap()));
oneOf(db).commitTransaction(txn1);
oneOf(db).endTransaction(txn1);
}});
vm.eventOccurred(new MessageAddedEvent(message, contactId));
@@ -640,20 +517,16 @@ public class ValidationManagerImplTest extends BrambleMockTestCase {
Transaction txn1 = new Transaction(null, false);
Transaction txn2 = new Transaction(null, false);
context.checking(new Expectations() {{
context.checking(new DbExpectations() {{
// Load the group
oneOf(db).startTransaction(true);
will(returnValue(txn));
oneOf(db).transactionWithResult(with(true), withDbCallable(txn));
oneOf(db).getGroup(txn, groupId);
will(returnValue(group));
oneOf(db).commitTransaction(txn);
oneOf(db).endTransaction(txn);
// Validate the message: valid
oneOf(validator).validateMessage(message, group);
will(returnValue(validResultWithDependencies));
// Store the validation result
oneOf(db).startTransaction(false);
will(returnValue(txn1));
oneOf(db).transaction(with(false), withDbRunnable(txn1));
oneOf(db).addMessageDependencies(txn1, message,
validResultWithDependencies.getDependencies());
// Check for invalid dependencies
@@ -668,11 +541,8 @@ public class ValidationManagerImplTest extends BrambleMockTestCase {
// Recursively invalidate dependents
oneOf(db).getMessageDependents(txn1, messageId);
will(returnValue(singletonMap(messageId2, UNKNOWN)));
oneOf(db).commitTransaction(txn1);
oneOf(db).endTransaction(txn1);
// Invalidate dependent in a new transaction
oneOf(db).startTransaction(false);
will(returnValue(txn2));
oneOf(db).transaction(with(false), withDbRunnable(txn2));
oneOf(db).getMessageState(txn2, messageId2);
will(returnValue(UNKNOWN));
oneOf(db).setMessageState(txn2, messageId2, INVALID);
@@ -680,8 +550,6 @@ public class ValidationManagerImplTest extends BrambleMockTestCase {
oneOf(db).deleteMessageMetadata(txn2, messageId2);
oneOf(db).getMessageDependents(txn2, messageId2);
will(returnValue(emptyMap()));
oneOf(db).commitTransaction(txn2);
oneOf(db).endTransaction(txn2);
}});
vm.eventOccurred(new MessageAddedEvent(message, contactId));
@@ -691,7 +559,7 @@ public class ValidationManagerImplTest extends BrambleMockTestCase {
public void testRecursiveInvalidation() throws Exception {
MessageId messageId3 = new MessageId(getRandomId());
MessageId messageId4 = new MessageId(getRandomId());
Map<MessageId, State> twoDependents = new LinkedHashMap<>();
Map<MessageId, MessageState> twoDependents = new LinkedHashMap<>();
twoDependents.put(messageId1, PENDING);
twoDependents.put(messageId2, PENDING);
Transaction txn = new Transaction(null, true);
@@ -702,20 +570,16 @@ public class ValidationManagerImplTest extends BrambleMockTestCase {
Transaction txn5 = new Transaction(null, false);
Transaction txn6 = new Transaction(null, false);
context.checking(new Expectations() {{
context.checking(new DbExpectations() {{
// Load the group
oneOf(db).startTransaction(true);
will(returnValue(txn));
oneOf(db).transactionWithResult(with(true), withDbCallable(txn));
oneOf(db).getGroup(txn, groupId);
will(returnValue(group));
oneOf(db).commitTransaction(txn);
oneOf(db).endTransaction(txn);
// Validate the message: invalid
oneOf(validator).validateMessage(message, group);
will(throwException(new InvalidMessageException()));
// Invalidate the message
oneOf(db).startTransaction(false);
will(returnValue(txn1));
oneOf(db).transaction(with(false), withDbRunnable(txn1));
oneOf(db).getMessageState(txn1, messageId);
will(returnValue(UNKNOWN));
oneOf(db).setMessageState(txn1, messageId, INVALID);
@@ -724,11 +588,8 @@ public class ValidationManagerImplTest extends BrambleMockTestCase {
// The message has two dependents: 1 and 2
oneOf(db).getMessageDependents(txn1, messageId);
will(returnValue(twoDependents));
oneOf(db).commitTransaction(txn1);
oneOf(db).endTransaction(txn1);
// Invalidate message 1
oneOf(db).startTransaction(false);
will(returnValue(txn2));
oneOf(db).transaction(with(false), withDbRunnable(txn2));
oneOf(db).getMessageState(txn2, messageId1);
will(returnValue(PENDING));
oneOf(db).setMessageState(txn2, messageId1, INVALID);
@@ -737,11 +598,8 @@ public class ValidationManagerImplTest extends BrambleMockTestCase {
// Message 1 has one dependent: 3
oneOf(db).getMessageDependents(txn2, messageId1);
will(returnValue(singletonMap(messageId3, PENDING)));
oneOf(db).commitTransaction(txn2);
oneOf(db).endTransaction(txn2);
// Invalidate message 2
oneOf(db).startTransaction(false);
will(returnValue(txn3));
oneOf(db).transaction(with(false), withDbRunnable(txn3));
oneOf(db).getMessageState(txn3, messageId2);
will(returnValue(PENDING));
oneOf(db).setMessageState(txn3, messageId2, INVALID);
@@ -750,11 +608,8 @@ public class ValidationManagerImplTest extends BrambleMockTestCase {
// Message 2 has one dependent: 3 (same dependent as 1)
oneOf(db).getMessageDependents(txn3, messageId2);
will(returnValue(singletonMap(messageId3, PENDING)));
oneOf(db).commitTransaction(txn3);
oneOf(db).endTransaction(txn3);
// Invalidate message 3 (via 1)
oneOf(db).startTransaction(false);
will(returnValue(txn4));
oneOf(db).transaction(with(false), withDbRunnable(txn4));
oneOf(db).getMessageState(txn4, messageId3);
will(returnValue(PENDING));
oneOf(db).setMessageState(txn4, messageId3, INVALID);
@@ -763,18 +618,12 @@ public class ValidationManagerImplTest extends BrambleMockTestCase {
// Message 3 has one dependent: 4
oneOf(db).getMessageDependents(txn4, messageId3);
will(returnValue(singletonMap(messageId4, PENDING)));
oneOf(db).commitTransaction(txn4);
oneOf(db).endTransaction(txn4);
// Invalidate message 3 (again, via 2)
oneOf(db).startTransaction(false);
will(returnValue(txn5));
oneOf(db).transaction(with(false), withDbRunnable(txn5));
oneOf(db).getMessageState(txn5, messageId3);
will(returnValue(INVALID)); // Already invalidated
oneOf(db).commitTransaction(txn5);
oneOf(db).endTransaction(txn5);
// Invalidate message 4 (via 1 and 3)
oneOf(db).startTransaction(false);
will(returnValue(txn6));
oneOf(db).transaction(with(false), withDbRunnable(txn6));
oneOf(db).getMessageState(txn6, messageId4);
will(returnValue(PENDING));
oneOf(db).setMessageState(txn6, messageId4, INVALID);
@@ -783,8 +632,6 @@ public class ValidationManagerImplTest extends BrambleMockTestCase {
// Message 4 has no dependents
oneOf(db).getMessageDependents(txn6, messageId4);
will(returnValue(emptyMap()));
oneOf(db).commitTransaction(txn6);
oneOf(db).endTransaction(txn6);
}});
vm.eventOccurred(new MessageAddedEvent(message, contactId));
@@ -796,10 +643,10 @@ public class ValidationManagerImplTest extends BrambleMockTestCase {
Message message4 = getMessage(groupId);
MessageId messageId3 = message3.getId();
MessageId messageId4 = message4.getId();
Map<MessageId, State> twoDependents = new LinkedHashMap<>();
Map<MessageId, MessageState> twoDependents = new LinkedHashMap<>();
twoDependents.put(messageId1, PENDING);
twoDependents.put(messageId2, PENDING);
Map<MessageId, State> twoDependencies = new LinkedHashMap<>();
Map<MessageId, MessageState> twoDependencies = new LinkedHashMap<>();
twoDependencies.put(messageId1, DELIVERED);
twoDependencies.put(messageId2, DELIVERED);
Transaction txn = new Transaction(null, true);
@@ -810,20 +657,16 @@ public class ValidationManagerImplTest extends BrambleMockTestCase {
Transaction txn5 = new Transaction(null, false);
Transaction txn6 = new Transaction(null, false);
context.checking(new Expectations() {{
context.checking(new DbExpectations() {{
// Load the group
oneOf(db).startTransaction(true);
will(returnValue(txn));
oneOf(db).transactionWithResult(with(true), withDbCallable(txn));
oneOf(db).getGroup(txn, groupId);
will(returnValue(group));
oneOf(db).commitTransaction(txn);
oneOf(db).endTransaction(txn);
// Validate the message: valid
oneOf(validator).validateMessage(message, group);
will(returnValue(validResult));
// Store the validation result
oneOf(db).startTransaction(false);
will(returnValue(txn1));
oneOf(db).transaction(with(false), withDbRunnable(txn1));
oneOf(db).mergeMessageMetadata(txn1, messageId, metadata);
// Deliver the message
oneOf(hook).incomingMessage(txn1, message, metadata);
@@ -832,11 +675,8 @@ public class ValidationManagerImplTest extends BrambleMockTestCase {
// The message has two pending dependents: 1 and 2
oneOf(db).getMessageDependents(txn1, messageId);
will(returnValue(twoDependents));
oneOf(db).commitTransaction(txn1);
oneOf(db).endTransaction(txn1);
// Check whether message 1 is ready to be delivered
oneOf(db).startTransaction(false);
will(returnValue(txn2));
oneOf(db).transaction(with(false), withDbRunnable(txn2));
oneOf(db).getMessageState(txn2, messageId1);
will(returnValue(PENDING));
oneOf(db).getMessageDependencies(txn2, messageId1);
@@ -855,11 +695,8 @@ public class ValidationManagerImplTest extends BrambleMockTestCase {
// Message 1 has one pending dependent: 3
oneOf(db).getMessageDependents(txn2, messageId1);
will(returnValue(singletonMap(messageId3, PENDING)));
oneOf(db).commitTransaction(txn2);
oneOf(db).endTransaction(txn2);
// Check whether message 2 is ready to be delivered
oneOf(db).startTransaction(false);
will(returnValue(txn3));
oneOf(db).transaction(with(false), withDbRunnable(txn3));
oneOf(db).getMessageState(txn3, messageId2);
will(returnValue(PENDING));
oneOf(db).getMessageDependencies(txn3, messageId2);
@@ -878,11 +715,8 @@ public class ValidationManagerImplTest extends BrambleMockTestCase {
// Message 2 has one pending dependent: 3 (same dependent as 1)
oneOf(db).getMessageDependents(txn3, messageId2);
will(returnValue(singletonMap(messageId3, PENDING)));
oneOf(db).commitTransaction(txn3);
oneOf(db).endTransaction(txn3);
// Check whether message 3 is ready to be delivered (via 1)
oneOf(db).startTransaction(false);
will(returnValue(txn4));
oneOf(db).transaction(with(false), withDbRunnable(txn4));
oneOf(db).getMessageState(txn4, messageId3);
will(returnValue(PENDING));
oneOf(db).getMessageDependencies(txn4, messageId3);
@@ -900,18 +734,12 @@ public class ValidationManagerImplTest extends BrambleMockTestCase {
// Message 3 has one pending dependent: 4
oneOf(db).getMessageDependents(txn4, messageId3);
will(returnValue(singletonMap(messageId4, PENDING)));
oneOf(db).commitTransaction(txn4);
oneOf(db).endTransaction(txn4);
// Check whether message 3 is ready to be delivered (again, via 2)
oneOf(db).startTransaction(false);
will(returnValue(txn5));
oneOf(db).transaction(with(false), withDbRunnable(txn5));
oneOf(db).getMessageState(txn5, messageId3);
will(returnValue(DELIVERED)); // Already delivered
oneOf(db).commitTransaction(txn5);
oneOf(db).endTransaction(txn5);
// Check whether message 4 is ready to be delivered (via 1 and 3)
oneOf(db).startTransaction(false);
will(returnValue(txn6));
oneOf(db).transaction(with(false), withDbRunnable(txn6));
oneOf(db).getMessageState(txn6, messageId4);
will(returnValue(PENDING));
oneOf(db).getMessageDependencies(txn6, messageId4);
@@ -930,8 +758,6 @@ public class ValidationManagerImplTest extends BrambleMockTestCase {
// Message 4 has no pending dependents
oneOf(db).getMessageDependents(txn6, messageId4);
will(returnValue(emptyMap()));
oneOf(db).commitTransaction(txn6);
oneOf(db).endTransaction(txn6);
}});
vm.eventOccurred(new MessageAddedEvent(message, contactId));
@@ -939,27 +765,23 @@ public class ValidationManagerImplTest extends BrambleMockTestCase {
@Test
public void testOnlyReadyPendingDependentsGetDelivered() throws Exception {
Map<MessageId, State> twoDependencies = new LinkedHashMap<>();
Map<MessageId, MessageState> twoDependencies = new LinkedHashMap<>();
twoDependencies.put(messageId, DELIVERED);
twoDependencies.put(messageId2, UNKNOWN);
Transaction txn = new Transaction(null, true);
Transaction txn1 = new Transaction(null, false);
Transaction txn2 = new Transaction(null, false);
context.checking(new Expectations() {{
context.checking(new DbExpectations() {{
// Load the group
oneOf(db).startTransaction(true);
will(returnValue(txn));
oneOf(db).transactionWithResult(with(true), withDbCallable(txn));
oneOf(db).getGroup(txn, groupId);
will(returnValue(group));
oneOf(db).commitTransaction(txn);
oneOf(db).endTransaction(txn);
// Validate the message: valid
oneOf(validator).validateMessage(message, group);
will(returnValue(validResult));
// Store the validation result
oneOf(db).startTransaction(false);
will(returnValue(txn1));
oneOf(db).transaction(with(false), withDbRunnable(txn1));
oneOf(db).mergeMessageMetadata(txn1, messageId, metadata);
// Deliver the message
oneOf(hook).incomingMessage(txn1, message, metadata);
@@ -968,17 +790,12 @@ public class ValidationManagerImplTest extends BrambleMockTestCase {
// Get any pending dependents
oneOf(db).getMessageDependents(txn1, messageId);
will(returnValue(singletonMap(messageId1, PENDING)));
oneOf(db).commitTransaction(txn1);
oneOf(db).endTransaction(txn1);
// Check whether the pending dependent is ready to be delivered
oneOf(db).startTransaction(false);
will(returnValue(txn2));
oneOf(db).transaction(with(false), withDbRunnable(txn2));
oneOf(db).getMessageState(txn2, messageId1);
will(returnValue(PENDING));
oneOf(db).getMessageDependencies(txn2, messageId1);
will(returnValue(twoDependencies));
oneOf(db).commitTransaction(txn2);
oneOf(db).endTransaction(txn2);
}});
vm.eventOccurred(new MessageAddedEvent(message, contactId));
@@ -1,8 +1,6 @@
package org.briarproject.bramble.system;
import org.briarproject.bramble.test.BrambleTestCase;
import org.briarproject.bramble.test.TestUtils;
import org.briarproject.bramble.util.OsUtils;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
@@ -10,48 +8,50 @@ import org.junit.Test;
import java.io.File;
import java.security.Provider;
import static org.briarproject.bramble.test.TestUtils.deleteTestDirectory;
import static org.briarproject.bramble.test.TestUtils.getTestDirectory;
import static org.briarproject.bramble.util.OsUtils.isLinux;
import static org.briarproject.bramble.util.OsUtils.isMac;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import static org.junit.Assume.assumeTrue;
public class LinuxSecureRandomProviderTest extends BrambleTestCase {
public class UnixSecureRandomProviderTest extends BrambleTestCase {
private final File testDir = TestUtils.getTestDirectory();
private final File testDir = getTestDirectory();
@Before
public void setUp() {
testDir.mkdirs();
assumeTrue(isLinux() || isMac());
assertTrue(testDir.mkdirs());
}
@Test
public void testGetProviderWritesToRandomDeviceOnFirstCall()
throws Exception {
if (!(OsUtils.isLinux())) {
System.err.println("WARNING: Skipping test, can't run on this OS");
return;
}
// Redirect the provider's output to a file
File urandom = new File(testDir, "urandom");
urandom.delete();
if (urandom.exists()) assertTrue(urandom.delete());
assertTrue(urandom.createNewFile());
assertEquals(0, urandom.length());
LinuxSecureRandomProvider p = new LinuxSecureRandomProvider(urandom);
UnixSecureRandomProvider p = new UnixSecureRandomProvider(urandom);
// Getting a provider should write entropy to the file
Provider provider = p.getProvider();
assertNotNull(provider);
assertEquals("LinuxPRNG", provider.getName());
assertEquals("UnixPRNG", provider.getName());
// There should be at least 16 bytes from the clock, 8 from the runtime
long length = urandom.length();
assertTrue(length >= 24);
// Getting another provider should not write to the file again
provider = p.getProvider();
assertNotNull(provider);
assertEquals("LinuxPRNG", provider.getName());
assertEquals("UnixPRNG", provider.getName());
assertEquals(length, urandom.length());
}
@After
public void tearDown() {
TestUtils.deleteTestDirectory(testDir);
deleteTestDirectory(testDir);
}
}
@@ -4,7 +4,6 @@ import org.briarproject.bramble.api.Bytes;
import org.briarproject.bramble.test.BrambleTestCase;
import org.briarproject.bramble.test.TestUtils;
import org.briarproject.bramble.util.IoUtils;
import org.briarproject.bramble.util.OsUtils;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
@@ -15,31 +14,33 @@ import java.io.FileOutputStream;
import java.util.HashSet;
import java.util.Set;
import static org.briarproject.bramble.test.TestUtils.deleteTestDirectory;
import static org.briarproject.bramble.test.TestUtils.getTestDirectory;
import static org.briarproject.bramble.util.OsUtils.isLinux;
import static org.briarproject.bramble.util.OsUtils.isMac;
import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import static org.junit.Assume.assumeTrue;
public class LinuxSecureRandomSpiTest extends BrambleTestCase {
public class UnixSecureRandomSpiTest extends BrambleTestCase {
private static final File RANDOM_DEVICE = new File("/dev/urandom");
private static final int SEED_BYTES = 32;
private final File testDir = TestUtils.getTestDirectory();
private final File testDir = getTestDirectory();
@Before
public void setUp() {
testDir.mkdirs();
assumeTrue(isLinux() || isMac());
assertTrue(testDir.mkdirs());
}
@Test
public void testSeedsAreDistinct() {
if (!(OsUtils.isLinux())) {
System.err.println("WARNING: Skipping test, can't run on this OS");
return;
}
Set<Bytes> seeds = new HashSet<>();
LinuxSecureRandomSpi engine = new LinuxSecureRandomSpi();
UnixSecureRandomSpi engine = new UnixSecureRandomSpi();
for (int i = 0; i < 1000; i++) {
byte[] seed = engine.engineGenerateSeed(SEED_BYTES);
assertEquals(SEED_BYTES, seed.length);
@@ -49,19 +50,15 @@ public class LinuxSecureRandomSpiTest extends BrambleTestCase {
@Test
public void testEngineSetSeedWritesToRandomDevice() throws Exception {
if (!(OsUtils.isLinux())) {
System.err.println("WARNING: Skipping test, can't run on this OS");
return;
}
// Redirect the engine's output to a file
File urandom = new File(testDir, "urandom");
urandom.delete();
if (urandom.exists()) assertTrue(urandom.delete());
assertTrue(urandom.createNewFile());
assertEquals(0, urandom.length());
// Generate a seed
byte[] seed = TestUtils.getRandomBytes(SEED_BYTES);
// Check that the engine writes the seed to the file
LinuxSecureRandomSpi engine = new LinuxSecureRandomSpi(RANDOM_DEVICE,
UnixSecureRandomSpi engine = new UnixSecureRandomSpi(RANDOM_DEVICE,
urandom);
engine.engineSetSeed(seed);
assertEquals(SEED_BYTES, urandom.length());
@@ -74,15 +71,11 @@ public class LinuxSecureRandomSpiTest extends BrambleTestCase {
@Test
public void testEngineNextBytesReadsFromRandomDevice() throws Exception {
if (!(OsUtils.isLinux())) {
System.err.println("WARNING: Skipping test, can't run on this OS");
return;
}
// Generate some entropy
byte[] entropy = TestUtils.getRandomBytes(SEED_BYTES);
// Write the entropy to a file
File urandom = new File(testDir, "urandom");
urandom.delete();
if (urandom.exists()) assertTrue(urandom.delete());
FileOutputStream out = new FileOutputStream(urandom);
out.write(entropy);
out.flush();
@@ -90,7 +83,7 @@ public class LinuxSecureRandomSpiTest extends BrambleTestCase {
assertTrue(urandom.exists());
assertEquals(SEED_BYTES, urandom.length());
// Check that the engine reads from the file
LinuxSecureRandomSpi engine = new LinuxSecureRandomSpi(urandom,
UnixSecureRandomSpi engine = new UnixSecureRandomSpi(urandom,
RANDOM_DEVICE);
byte[] b = new byte[SEED_BYTES];
engine.engineNextBytes(b);
@@ -99,15 +92,11 @@ public class LinuxSecureRandomSpiTest extends BrambleTestCase {
@Test
public void testEngineGenerateSeedReadsFromRandomDevice() throws Exception {
if (!(OsUtils.isLinux())) {
System.err.println("WARNING: Skipping test, can't run on this OS");
return;
}
// Generate some entropy
byte[] entropy = TestUtils.getRandomBytes(SEED_BYTES);
// Write the entropy to a file
File urandom = new File(testDir, "urandom");
urandom.delete();
if (urandom.exists()) assertTrue(urandom.delete());
FileOutputStream out = new FileOutputStream(urandom);
out.write(entropy);
out.flush();
@@ -115,7 +104,7 @@ public class LinuxSecureRandomSpiTest extends BrambleTestCase {
assertTrue(urandom.exists());
assertEquals(SEED_BYTES, urandom.length());
// Check that the engine reads from the file
LinuxSecureRandomSpi engine = new LinuxSecureRandomSpi(urandom,
UnixSecureRandomSpi engine = new UnixSecureRandomSpi(urandom,
RANDOM_DEVICE);
byte[] b = engine.engineGenerateSeed(SEED_BYTES);
assertArrayEquals(entropy, b);
@@ -123,6 +112,6 @@ public class LinuxSecureRandomSpiTest extends BrambleTestCase {
@After
public void tearDown() {
TestUtils.deleteTestDirectory(testDir);
deleteTestDirectory(testDir);
}
}
@@ -2,6 +2,7 @@ package org.briarproject.bramble.test;
import org.briarproject.bramble.api.db.DbCallable;
import org.briarproject.bramble.api.db.DbRunnable;
import org.briarproject.bramble.api.db.NullableDbCallable;
import org.briarproject.bramble.api.db.Transaction;
import org.jmock.Expectations;
@@ -21,4 +22,12 @@ public class DbExpectations extends Expectations {
return null;
}
protected <R, E extends Exception> NullableDbCallable<R, E> withNullableDbCallable(
Transaction txn) {
addParameterMatcher(any(NullableDbCallable.class));
currentBuilder().setAction(
new RunTransactionWithNullableResultAction(txn));
return null;
}
}
@@ -0,0 +1,28 @@
package org.briarproject.bramble.test;
import org.briarproject.bramble.api.db.NullableDbCallable;
import org.briarproject.bramble.api.db.Transaction;
import org.hamcrest.Description;
import org.jmock.api.Action;
import org.jmock.api.Invocation;
public class RunTransactionWithNullableResultAction implements Action {
private final Transaction txn;
public RunTransactionWithNullableResultAction(Transaction txn) {
this.txn = txn;
}
@Override
public Object invoke(Invocation invocation) throws Throwable {
NullableDbCallable task =
(NullableDbCallable) invocation.getParameter(1);
return task.call(txn);
}
@Override
public void describeTo(Description description) {
description.appendText("runs a task inside a database transaction");
}
}
@@ -15,6 +15,7 @@ import org.briarproject.bramble.api.plugin.simplex.SimplexPluginFactory;
import org.briarproject.bramble.api.transport.KeySetId;
import org.briarproject.bramble.api.transport.StreamContext;
import org.briarproject.bramble.test.BrambleMockTestCase;
import org.briarproject.bramble.test.DbExpectations;
import org.jmock.Expectations;
import org.jmock.lib.concurrent.DeterministicExecutor;
import org.junit.Before;
@@ -35,6 +36,7 @@ import static org.briarproject.bramble.test.TestUtils.getSecretKey;
import static org.briarproject.bramble.test.TestUtils.getTransportId;
import static org.briarproject.bramble.util.StringUtils.getRandomString;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNull;
public class KeyManagerImplTest extends BrambleMockTestCase {
@@ -77,7 +79,7 @@ public class KeyManagerImplTest extends BrambleMockTestCase {
singletonList(pluginFactory);
int maxLatency = 1337;
context.checking(new Expectations() {{
context.checking(new DbExpectations() {{
oneOf(pluginConfig).getSimplexFactories();
will(returnValue(factories));
oneOf(pluginFactory).getId();
@@ -89,13 +91,10 @@ public class KeyManagerImplTest extends BrambleMockTestCase {
.createTransportKeyManager(transportId, maxLatency);
will(returnValue(transportKeyManager));
oneOf(pluginConfig).getDuplexFactories();
oneOf(db).startTransaction(false);
will(returnValue(txn));
oneOf(db).transaction(with(false), withDbRunnable(txn));
oneOf(db).getContacts(txn);
will(returnValue(contacts));
oneOf(transportKeyManager).start(txn);
oneOf(db).commitTransaction(txn);
oneOf(db).endTransaction(txn);
}});
keyManager.startService();
@@ -121,25 +120,21 @@ public class KeyManagerImplTest extends BrambleMockTestCase {
@Test
public void testGetStreamContextForInactiveContact() throws Exception {
assertEquals(null,
keyManager.getStreamContext(inactiveContactId, transportId));
assertNull(keyManager.getStreamContext(inactiveContactId, transportId));
}
@Test
public void testGetStreamContextForUnknownTransport() throws Exception {
assertEquals(null,
keyManager.getStreamContext(contactId, unknownTransportId));
assertNull(keyManager.getStreamContext(contactId, unknownTransportId));
}
@Test
public void testGetStreamContextForContact() throws Exception {
context.checking(new Expectations() {{
oneOf(db).startTransaction(false);
will(returnValue(txn));
context.checking(new DbExpectations() {{
oneOf(db).transactionWithNullableResult(with(false),
withNullableDbCallable(txn));
oneOf(transportKeyManager).getStreamContext(txn, contactId);
will(returnValue(streamContext));
oneOf(db).commitTransaction(txn);
oneOf(db).endTransaction(txn);
}});
assertEquals(streamContext,
@@ -149,19 +144,16 @@ public class KeyManagerImplTest extends BrambleMockTestCase {
@Test
public void testGetStreamContextForTagAndUnknownTransport()
throws Exception {
assertEquals(null,
keyManager.getStreamContext(unknownTransportId, tag));
assertNull(keyManager.getStreamContext(unknownTransportId, tag));
}
@Test
public void testGetStreamContextForTag() throws Exception {
context.checking(new Expectations() {{
oneOf(db).startTransaction(false);
will(returnValue(txn));
context.checking(new DbExpectations() {{
oneOf(db).transactionWithNullableResult(with(false),
withNullableDbCallable(txn));
oneOf(transportKeyManager).getStreamContext(txn, tag);
will(returnValue(streamContext));
oneOf(db).commitTransaction(txn);
oneOf(db).endTransaction(txn);
}});
assertEquals(streamContext,
@@ -178,7 +170,7 @@ public class KeyManagerImplTest extends BrambleMockTestCase {
keyManager.eventOccurred(event);
executor.runUntilIdle();
assertEquals(null, keyManager.getStreamContext(contactId, transportId));
assertNull(keyManager.getStreamContext(contactId, transportId));
}
@Test
@@ -186,13 +178,11 @@ public class KeyManagerImplTest extends BrambleMockTestCase {
ContactStatusChangedEvent event =
new ContactStatusChangedEvent(inactiveContactId, true);
context.checking(new Expectations() {{
oneOf(db).startTransaction(false);
will(returnValue(txn));
context.checking(new DbExpectations() {{
oneOf(db).transactionWithNullableResult(with(false),
withNullableDbCallable(txn));
oneOf(transportKeyManager).getStreamContext(txn, inactiveContactId);
will(returnValue(streamContext));
oneOf(db).commitTransaction(txn);
oneOf(db).endTransaction(txn);
}});
keyManager.eventOccurred(event);

Some files were not shown because too many files have changed in this diff Show More