Skip to content

Commit 6537921

Browse files
authored
Fix ConcurrentModificationException. (#984)
* Fix/supress warnings. * fix: Set XML parsing settings. * ref: Reuse ParticipantInfo.toEndpoint. * fix: Fix ConcurrentModificationException when bridge count changes.
1 parent 1e258e1 commit 6537921

File tree

7 files changed

+31
-33
lines changed

7 files changed

+31
-33
lines changed

jicofo-common/src/main/kotlin/org/jitsi/jicofo/conference/source/Source.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -95,7 +95,7 @@ data class Source(
9595
put("media_type", mediaType.toString())
9696
put("name", name ?: "null")
9797
put("msid", msid ?: "null")
98-
put("videoType", videoType.toString() ?: "null")
98+
put("videoType", videoType.toString())
9999
}
100100

101101
companion object {

jicofo-selector/src/main/kotlin/org/jitsi/jicofo/bridge/colibri/Colibri2Session.kt

Lines changed: 4 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,6 @@ import org.jitsi.utils.OrderedJsonObject
2525
import org.jitsi.utils.logging2.Logger
2626
import org.jitsi.utils.logging2.createChildLogger
2727
import org.jitsi.xmpp.extensions.colibri.WebSocketPacketExtension
28-
import org.jitsi.xmpp.extensions.colibri2.Capability
2928
import org.jitsi.xmpp.extensions.colibri2.Colibri2Endpoint
3029
import org.jitsi.xmpp.extensions.colibri2.Colibri2Relay
3130
import org.jitsi.xmpp.extensions.colibri2.ConferenceModifiedIQ
@@ -77,19 +76,7 @@ internal class Colibri2Session(
7776
internal fun sendAllocationRequest(participant: ParticipantInfo): StanzaCollector {
7877

7978
val request = createRequest(!created)
80-
val endpoint = Colibri2Endpoint.getBuilder().apply {
81-
setId(participant.id)
82-
setCreate(true)
83-
if (participant.sources.isNotEmpty()) {
84-
setSources(participant.sources.toColibriMediaSources())
85-
}
86-
setStatsId(participant.statsId)
87-
if (participant.supportsSourceNames) {
88-
addCapability(Capability.CAP_SOURCE_NAME_SUPPORT)
89-
}
90-
if (participant.useSsrcRewriting) {
91-
addCapability(Capability.CAP_SSRC_REWRITING_SUPPORT)
92-
}
79+
val endpoint = participant.toEndpoint(create = true, expire = false).apply {
9380
if (participant.audioMuted || participant.videoMuted) {
9481
setForceMute(participant.audioMuted, participant.videoMuted)
9582
}
@@ -417,7 +404,7 @@ internal class Colibri2Session(
417404
setId(id)
418405
}
419406
val endpoints = Endpoints.getBuilder()
420-
endpoints.addEndpoint(participant.toEndpoint(create = create, expire = false))
407+
endpoints.addEndpoint(participant.toEndpoint(create = create, expire = false).build())
421408
relay.setEndpoints(endpoints.build())
422409
request.addRelay(relay.build())
423410
sendRequest(request.build(), "Relay.updateParticipant")
@@ -429,7 +416,7 @@ internal class Colibri2Session(
429416
val relay = Colibri2Relay.getBuilder().apply { setId(id) }
430417
val endpoints = Endpoints.getBuilder()
431418

432-
participants.forEach { endpoints.addEndpoint(it.toEndpoint(create = false, expire = true)) }
419+
participants.forEach { endpoints.addEndpoint(it.toEndpoint(create = false, expire = true).build()) }
433420

434421
relay.setEndpoints(endpoints.build())
435422
request.addRelay(relay.build())
@@ -461,7 +448,7 @@ internal class Colibri2Session(
461448
)
462449

463450
val endpoints = Endpoints.getBuilder()
464-
participants.forEach { endpoints.addEndpoint(it.toEndpoint(create = true, expire = false)) }
451+
participants.forEach { endpoints.addEndpoint(it.toEndpoint(create = true, expire = false).build()) }
465452
relay.setEndpoints(endpoints.build())
466453

467454
relay.setTransport(

jicofo-selector/src/main/kotlin/org/jitsi/jicofo/bridge/colibri/Extensions.kt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -105,7 +105,7 @@ internal fun ParticipantInfo.toEndpoint(
105105
create: Boolean,
106106
/** Whether the request should have the "expire" flag set. */
107107
expire: Boolean
108-
): Colibri2Endpoint = Colibri2Endpoint.getBuilder().apply {
108+
): Colibri2Endpoint.Builder = Colibri2Endpoint.getBuilder().apply {
109109
setId(id)
110110
if (create) {
111111
setCreate(true)
@@ -124,7 +124,7 @@ internal fun ParticipantInfo.toEndpoint(
124124
if (expire) {
125125
setExpire(true)
126126
}
127-
}.build()
127+
}
128128

129129
internal fun AbstractXMPPConnection.sendIqAndHandleResponseAsync(iq: IQ, block: (IQ?) -> Unit) {
130130
val stanzaCollector = createStanzaCollectorAndSend(iq)

jicofo/src/main/java/org/jitsi/jicofo/conference/JitsiMeetConferenceImpl.java

Lines changed: 15 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -187,7 +187,7 @@ public class JitsiMeetConferenceImpl
187187
/**
188188
* The conference properties that we advertise in presence in the XMPP MUC.
189189
*/
190-
private final ConferenceProperties conferenceProperties = new ConferenceProperties();
190+
private final ConcurrentHashMap<String, String> conferenceProperties = new ConcurrentHashMap<>();
191191

192192
/**
193193
* See {@link JitsiMeetConference#includeInStatistics()}
@@ -512,7 +512,7 @@ else if (ConferenceConfig.config.enableAutoOwner())
512512
Boolean.TRUE.toString(),
513513
false);
514514

515-
presenceExtensions.add(ConferenceProperties.clone(conferenceProperties));
515+
presenceExtensions.add(createConferenceProperties());
516516

517517
// updates presence with presenceExtensions and sends it
518518
chatRoom.modifyPresence(null, presenceExtensions);
@@ -524,7 +524,7 @@ else if (ConferenceConfig.config.enableAutoOwner())
524524
* @param key the key of the property.
525525
* @param value the value of the property.
526526
*/
527-
private void setConferenceProperty(String key, String value)
527+
private void setConferenceProperty(@NotNull String key, @NotNull String value)
528528
{
529529
setConferenceProperty(key, value, true);
530530
}
@@ -539,15 +539,22 @@ private void setConferenceProperty(String key, String value)
539539
* and {@code false} to only add the property locally. This is useful to
540540
* allow updating multiple properties but sending a single presence update.
541541
*/
542-
private void setConferenceProperty(String key, String value, boolean updatePresence)
542+
private void setConferenceProperty(@NotNull String key, @NotNull String value, boolean updatePresence)
543543
{
544-
conferenceProperties.put(key, value);
545-
if (updatePresence && chatRoom != null)
544+
String oldValue = conferenceProperties.put(key, value);
545+
if (updatePresence && chatRoom != null && !value.equals(oldValue))
546546
{
547-
chatRoom.setPresenceExtension(ConferenceProperties.clone(conferenceProperties), false);
547+
chatRoom.setPresenceExtension(createConferenceProperties(), false);
548548
}
549549
}
550550

551+
private ConferenceProperties createConferenceProperties()
552+
{
553+
ConferenceProperties conferenceProperties = new ConferenceProperties();
554+
this.conferenceProperties.forEach(conferenceProperties::put);
555+
return conferenceProperties;
556+
}
557+
551558
/**
552559
* Process the new number of audio senders reported by the chat room.
553560
*/
@@ -1564,10 +1571,7 @@ public OrderedJsonObject getDebugState()
15641571
o.put("colibri_session_manager", colibriSessionManager.getDebugState());
15651572
}
15661573
OrderedJsonObject conferencePropertiesJson = new OrderedJsonObject();
1567-
for (ConferenceProperties.ConferenceProperty conferenceProperty : conferenceProperties.getProperties())
1568-
{
1569-
conferencePropertiesJson.put(conferenceProperty.getKey(), conferenceProperty.getValue());
1570-
}
1574+
conferenceProperties.forEach(conferencePropertiesJson::put);
15711575
o.put("conference_properties", conferencePropertiesJson);
15721576
o.put("include_in_statistics", includeInStatistics);
15731577
o.put("conference_sources", conferenceSources.toJson());

jicofo/src/main/java/org/jitsi/jicofo/rest/Debug.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,8 @@ public String confDebug(@PathParam("confId") String confId)
6161
@Path("/conferences")
6262
@Produces(MediaType.APPLICATION_JSON)
6363
@NotNull
64-
public String conferences(@PathParam("confId") String confId)
64+
@SuppressWarnings("unchecked")
65+
public String conferences()
6566
{
6667
JSONArray conferencesJson = new JSONArray();
6768
for (JitsiMeetConference c : jicofoServices.getFocusManager().getAllConferences())

jicofo/src/main/kotlin/org/jitsi/jicofo/xmpp/MuteIqHandler.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,7 @@ private fun handleRequest(request: MuteRequest): IqProcessingResult {
8888
val jidToMute = request.jidToMute
8989
val doMute = request.doMute
9090
val mediaType = request.mediaType
91-
if (doMute == null || jidToMute == null || mediaType == null) {
91+
if (doMute == null || jidToMute == null) {
9292
logger.warn("Mute request missing required fields: ${request.iq.toXML()}")
9393
return RejectedWithError(request.iq, StanzaError.Condition.bad_request)
9494
}

jicofo/src/main/kotlin/org/jitsi/jicofo/xmpp/Smack.kt

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,12 @@ import org.jivesoftware.smack.provider.ProviderManager
5757
import org.jivesoftware.smackx.bytestreams.socks5.Socks5Proxy
5858

5959
fun initializeSmack() {
60+
System.setProperty("jdk.xml.entityExpansionLimit", "0")
61+
System.setProperty("jdk.xml.maxOccurLimit", "0")
62+
System.setProperty("jdk.xml.elementAttributeLimit", "524288")
63+
System.setProperty("jdk.xml.totalEntitySizeLimit", "0")
64+
System.setProperty("jdk.xml.maxXMLNameLimit", "524288")
65+
System.setProperty("jdk.xml.entityReplacementLimit", "0")
6066
SmackConfiguration.setDefaultReplyTimeout(15000)
6167
// if there is a parsing error, do not break the connection to the server(the default behaviour) as we need it for
6268
// the other conferences.

0 commit comments

Comments
 (0)