Skip to content
GitLab
Menu
Projects
Groups
Snippets
/
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
Menu
Open sidebar
The Tor Project
Network Health
Metrics
Library
Commits
f19e54b7
Commit
f19e54b7
authored
Jun 30, 2021
by
Iain Learmonth
Browse files
Adds support for Bridgestrap metrics
#40006
parent
eadbf01d
Pipeline
#9989
passed with stage
in 2 minutes and 30 seconds
Changes
8
Pipelines
1
Hide whitespace changes
Inline
Side-by-side
src/main/java/org/torproject/descriptor/BridgestrapStats.java
0 → 100644
View file @
f19e54b7
/* Copyright 2019--2020 The Tor Project
* Copyright 2021 SR2 Communications Limited
* See LICENSE for licensing information */
package
org.torproject.descriptor
;
import
org.torproject.descriptor.Descriptor
;
import
java.time.Duration
;
import
java.time.LocalDateTime
;
import
java.util.List
;
import
java.util.Optional
;
public
interface
BridgestrapStats
extends
Descriptor
{
LocalDateTime
bridgestrapStatsEnd
();
Duration
bridgestrapStatsIntervalLength
();
int
bridgestrapCachedRequests
();
Optional
<
List
<
BridgestrapTestResult
>>
bridgestrapTests
();
}
src/main/java/org/torproject/descriptor/BridgestrapTestResult.java
0 → 100644
View file @
f19e54b7
/* Copyright 2021 SR2 Communications Limited
* See LICENSE for licensing information */
package
org.torproject.descriptor
;
import
java.util.Optional
;
public
interface
BridgestrapTestResult
{
boolean
isReachable
();
Optional
<
String
>
hashedFingerprint
();
}
src/main/java/org/torproject/descriptor/impl/BridgestrapStatsImpl.java
0 → 100644
View file @
f19e54b7
/* Copyright 2019--2020 The Tor Project
* Copyright 2021 SR2 Communications Limited
* See LICENSE for licensing information */
package
org.torproject.descriptor.impl
;
import
org.torproject.descriptor.BridgestrapStats
;
import
org.torproject.descriptor.BridgestrapTestResult
;
import
org.torproject.descriptor.DescriptorParseException
;
import
java.io.File
;
import
java.time.Duration
;
import
java.time.LocalDateTime
;
import
java.util.ArrayList
;
import
java.util.EnumSet
;
import
java.util.List
;
import
java.util.Optional
;
import
java.util.Scanner
;
import
java.util.Set
;
public
class
BridgestrapStatsImpl
extends
DescriptorImpl
implements
BridgestrapStats
{
private
static
final
Set
<
Key
>
exactlyOnce
=
EnumSet
.
of
(
Key
.
BRIDGESTRAP_STATS_END
);
private
static
final
Set
<
Key
>
atMostOnce
=
EnumSet
.
of
(
Key
.
BRIDGESTRAP_CACHED_REQUESTS
);
BridgestrapStatsImpl
(
byte
[]
rawDescriptorBytes
,
int
[]
offsetAndLength
,
File
descriptorFile
)
throws
DescriptorParseException
{
super
(
rawDescriptorBytes
,
offsetAndLength
,
descriptorFile
,
false
);
this
.
parseDescriptorBytes
();
this
.
checkExactlyOnceKeys
(
exactlyOnce
);
this
.
checkFirstKey
(
Key
.
BRIDGESTRAP_STATS_END
);
this
.
checkAtMostOnceKeys
(
atMostOnce
);
this
.
clearParsedKeys
();
}
BridgestrapStatsImpl
(
byte
[]
rawDescriptorBytes
,
File
descriptorFile
)
throws
DescriptorParseException
{
this
(
rawDescriptorBytes
,
new
int
[]{
0
,
rawDescriptorBytes
.
length
},
descriptorFile
);
}
private
void
parseDescriptorBytes
()
throws
DescriptorParseException
{
Scanner
scanner
=
this
.
newScanner
().
useDelimiter
(
NL
);
while
(
scanner
.
hasNext
())
{
String
line
=
scanner
.
next
();
if
(
line
.
startsWith
(
"@"
))
{
continue
;
}
String
[]
parts
=
line
.
split
(
"[ \t]+"
);
Key
key
=
Key
.
get
(
parts
[
0
]);
switch
(
key
)
{
case
BRIDGESTRAP_STATS_END:
this
.
parseBridgestrapStatsEnd
(
line
,
parts
);
break
;
case
BRIDGESTRAP_CACHED_REQUESTS:
this
.
parseBridgestrapCachedRequests
(
line
,
parts
);
break
;
case
BRIDGESTRAP_TEST:
this
.
parseBridgestrapTest
(
line
,
parts
);
break
;
case
INVALID:
default
:
ParseHelper
.
parseKeyword
(
line
,
parts
[
0
]);
if
(
this
.
unrecognizedLines
==
null
)
{
this
.
unrecognizedLines
=
new
ArrayList
<>();
}
this
.
unrecognizedLines
.
add
(
line
);
}
}
}
private
void
parseBridgestrapStatsEnd
(
String
line
,
String
[]
parts
)
throws
DescriptorParseException
{
if
(
parts
.
length
<
5
||
parts
[
3
].
length
()
<
2
||
!
parts
[
3
].
startsWith
(
"("
)
||
!
parts
[
4
].
equals
(
"s)"
))
{
throw
new
DescriptorParseException
(
"Illegal line '"
+
line
+
"'."
);
}
this
.
bridgestrapStatsEnd
=
ParseHelper
.
parseLocalDateTime
(
line
,
parts
,
1
,
2
);
this
.
bridgestrapStatsIntervalLength
=
ParseHelper
.
parseDuration
(
line
,
parts
[
3
].
substring
(
1
));
}
private
void
parseBridgestrapCachedRequests
(
String
line
,
String
[]
parts
)
throws
DescriptorParseException
{
if
(
parts
.
length
<
2
)
{
throw
new
DescriptorParseException
(
"Illegal line '"
+
line
+
"'."
);
}
try
{
this
.
bridgestrapCachedRequests
=
Integer
.
parseInt
(
parts
[
1
]);
}
catch
(
NumberFormatException
e
)
{
throw
new
DescriptorParseException
(
"Illegal number format '"
+
line
+
"'."
);
}
}
private
void
parseBridgestrapTest
(
String
line
,
String
[]
parts
)
throws
DescriptorParseException
{
if
(
parts
.
length
<
2
)
{
throw
new
DescriptorParseException
(
"Illegal line '"
+
line
+
"'."
);
}
if
(
null
==
this
.
bridgestrapTests
)
{
this
.
bridgestrapTests
=
new
ArrayList
<>();
}
boolean
isReachable
=
Boolean
.
parseBoolean
(
parts
[
1
]);
String
fingerprint
=
null
;
if
(
parts
.
length
>=
3
)
{
fingerprint
=
parts
[
2
];
}
this
.
bridgestrapTests
.
add
(
new
BridgestrapTestResultImpl
(
isReachable
,
fingerprint
));
}
private
LocalDateTime
bridgestrapStatsEnd
;
@Override
public
LocalDateTime
bridgestrapStatsEnd
()
{
return
this
.
bridgestrapStatsEnd
;
}
private
Duration
bridgestrapStatsIntervalLength
;
@Override
public
Duration
bridgestrapStatsIntervalLength
()
{
return
this
.
bridgestrapStatsIntervalLength
;
}
private
int
bridgestrapCachedRequests
;
@Override
public
int
bridgestrapCachedRequests
()
{
return
this
.
bridgestrapCachedRequests
;
}
private
List
<
BridgestrapTestResult
>
bridgestrapTests
;
@Override
public
Optional
<
List
<
BridgestrapTestResult
>>
bridgestrapTests
()
{
return
Optional
.
ofNullable
(
this
.
bridgestrapTests
);
}
}
\ No newline at end of file
src/main/java/org/torproject/descriptor/impl/BridgestrapTestResultImpl.java
0 → 100644
View file @
f19e54b7
/* Copyright 2021 SR2 Communications Limited
* See LICENSE for licensing information */
package
org.torproject.descriptor.impl
;
import
org.torproject.descriptor.BridgestrapTestResult
;
import
java.util.Optional
;
public
class
BridgestrapTestResultImpl
implements
BridgestrapTestResult
{
private
final
boolean
isReachable
;
private
final
String
hashedFingerprint
;
public
BridgestrapTestResultImpl
(
boolean
reachable
,
String
hashedFingerprint
)
{
this
.
isReachable
=
reachable
;
this
.
hashedFingerprint
=
hashedFingerprint
;
}
@Override
public
boolean
isReachable
()
{
return
this
.
isReachable
;
}
@Override
public
Optional
<
String
>
hashedFingerprint
()
{
return
Optional
.
ofNullable
(
this
.
hashedFingerprint
);
}
}
src/main/java/org/torproject/descriptor/impl/DescriptorParserImpl.java
View file @
f19e54b7
...
...
@@ -140,7 +140,12 @@ public class DescriptorParserImpl implements DescriptorParser {
||
firstLines
.
startsWith
(
Key
.
BRIDGEDB_METRICS_END
.
keyword
+
SP
)
||
firstLines
.
contains
(
NL
+
Key
.
BRIDGEDB_METRICS_END
.
keyword
+
SP
))
{
return
this
.
parseOneOrMoreDescriptors
(
rawDescriptorBytes
,
sourceFile
,
Key
.
BRIDGEDB_METRICS_END
,
BridgedbMetricsImpl
.
class
);
Key
.
BRIDGEDB_METRICS_END
,
BridgedbMetricsImpl
.
class
);
}
else
if
(
firstLines
.
startsWith
(
"@type bridgestrap-stats 1."
)
||
firstLines
.
startsWith
(
Key
.
BRIDGESTRAP_STATS_END
.
keyword
+
SP
)
||
firstLines
.
contains
(
NL
+
Key
.
BRIDGESTRAP_STATS_END
.
keyword
+
SP
))
{
return
this
.
parseOneOrMoreDescriptors
(
rawDescriptorBytes
,
sourceFile
,
Key
.
BRIDGESTRAP_STATS_END
,
BridgestrapStatsImpl
.
class
);
}
else
if
(
firstLines
.
startsWith
(
"@type bandwidth-file 1."
)
||
firstLines
.
matches
(
"(?s)[0-9]{10}\\n.*"
))
{
/* Identifying bandwidth files by a 10-digit timestamp in the first line
...
...
src/main/java/org/torproject/descriptor/impl/Key.java
View file @
f19e54b7
...
...
@@ -23,6 +23,9 @@ public enum Key {
BRIDGEDB_METRICS_END
(
"bridgedb-metrics-end"
),
BRIDGEDB_METRICS_VERSION
(
"bridgedb-metrics-version"
),
BRIDGEDB_METRIC_COUNT
(
"bridgedb-metric-count"
),
BRIDGESTRAP_STATS_END
(
"bridgestrap-stats-end"
),
BRIDGESTRAP_CACHED_REQUESTS
(
"bridgestrap-cached-requests"
),
BRIDGESTRAP_TEST
(
"bridgestrap-test"
),
BRIDGE_DISTRIBUTION_REQUEST
(
"bridge-distribution-request"
),
BRIDGE_IPS
(
"bridge-ips"
),
BRIDGE_IP_TRANSPORTS
(
"bridge-ip-transports"
),
...
...
src/test/java/org/torproject/descriptor/impl/BridgestrapStatsImplTest.java
0 → 100644
View file @
f19e54b7
/* Copyright 2019--2020 The Tor Project
* Copyright 2021 SR2 Communications Limited
* See LICENSE for licensing information */
package
org.torproject.descriptor.impl
;
import
static
org
.
junit
.
Assert
.
assertEquals
;
import
static
org
.
junit
.
Assert
.
assertFalse
;
import
static
org
.
junit
.
Assert
.
assertNotNull
;
import
static
org
.
junit
.
Assert
.
assertTrue
;
import
org.torproject.descriptor.BridgestrapStats
;
import
org.torproject.descriptor.BridgestrapTestResult
;
import
org.torproject.descriptor.DescriptorParseException
;
import
org.apache.commons.compress.utils.IOUtils
;
import
org.junit.Test
;
import
java.io.IOException
;
import
java.io.InputStream
;
import
java.net.URL
;
import
java.time.LocalDate
;
import
java.time.LocalDateTime
;
import
java.time.LocalTime
;
import
java.util.List
;
import
java.util.Optional
;
public
class
BridgestrapStatsImplTest
{
@Test
public
void
testParse
()
throws
IOException
,
DescriptorParseException
{
URL
resource
=
getClass
().
getClassLoader
().
getResource
(
"bridgestrap/bridgestrap-collector"
);
assertNotNull
(
resource
);
InputStream
dataInputStream
=
resource
.
openStream
();
assertNotNull
(
dataInputStream
);
byte
[]
rawDescriptorBytes
=
IOUtils
.
toByteArray
(
dataInputStream
);
BridgestrapStats
bridgestrapStats
=
new
BridgestrapStatsImpl
(
rawDescriptorBytes
,
new
int
[]{
0
,
rawDescriptorBytes
.
length
},
null
);
assertEquals
(
LocalDateTime
.
of
(
LocalDate
.
of
(
2021
,
7
,
20
),
LocalTime
.
of
(
19
,
11
,
16
)),
bridgestrapStats
.
bridgestrapStatsEnd
());
assertEquals
(
5051
,
bridgestrapStats
.
bridgestrapCachedRequests
());
Optional
<
List
<
BridgestrapTestResult
>>
resultList
=
bridgestrapStats
.
bridgestrapTests
();
assertTrue
(
resultList
.
isPresent
());
assertEquals
(
3281
,
resultList
.
get
().
size
());
BridgestrapTestResult
first
=
resultList
.
get
().
get
(
0
);
assertFalse
(
first
.
isReachable
());
assertTrue
(
first
.
hashedFingerprint
().
isPresent
());
assertEquals
(
"00795E6F05824B2DE96411735BF5D7A163CE63C2"
,
first
.
hashedFingerprint
().
get
());
BridgestrapTestResult
second
=
resultList
.
get
().
get
(
1
);
assertFalse
(
second
.
isReachable
());
assertTrue
(
second
.
hashedFingerprint
().
isPresent
());
assertEquals
(
"0089AD6FED844EA585DCC5127B6BD757C34F22C3"
,
second
.
hashedFingerprint
().
get
());
BridgestrapTestResult
last
=
resultList
.
get
().
get
(
resultList
.
get
().
size
()
-
1
);
assertTrue
(
last
.
isReachable
());
assertTrue
(
last
.
hashedFingerprint
().
isPresent
());
assertEquals
(
"FFD817FAAA36F185F43474F74C446EA8D95EC38F"
,
last
.
hashedFingerprint
().
get
());
}
}
src/test/resources/bridgestrap/bridgestrap-collector
0 → 100644
View file @
f19e54b7
This source diff could not be displayed because it is too large. You can
view the blob
instead.
Write
Preview
Supports
Markdown
0%
Try again
or
attach a new file
.
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment