use of org.eclipse.milo.opcua.stack.core.types.structured.ServiceFault in project milo by eclipse.
the class UascServerSymmetricHandler method sendServiceFault.
private void sendServiceFault(ChannelHandlerContext ctx, long requestId, UInteger requestHandle, Throwable fault) {
StatusCode statusCode = UaException.extract(fault).map(UaException::getStatusCode).orElse(StatusCode.BAD);
ServiceFault serviceFault = new ServiceFault(new ResponseHeader(DateTime.now(), requestHandle, statusCode, null, null, null));
serializationQueue.encode((binaryEncoder, chunkEncoder) -> {
ByteBuf messageBuffer = BufferUtil.pooledBuffer();
try {
binaryEncoder.setBuffer(messageBuffer);
binaryEncoder.writeMessage(null, serviceFault);
checkMessageSize(messageBuffer);
EncodedMessage encodedMessage = chunkEncoder.encodeSymmetric(secureChannel, requestId, messageBuffer, MessageType.SecureMessage);
CompositeByteBuf chunkComposite = BufferUtil.compositeBuffer();
for (ByteBuf chunk : encodedMessage.getMessageChunks()) {
chunkComposite.addComponent(chunk);
chunkComposite.writerIndex(chunkComposite.writerIndex() + chunk.readableBytes());
}
ctx.writeAndFlush(chunkComposite, ctx.voidPromise());
} catch (MessageEncodeException e) {
logger.error("Error encoding {}: {}", serviceFault, e.getMessage(), e);
} catch (UaSerializationException e) {
logger.error("Error serializing ServiceFault: {}", e.getStatusCode(), e);
} finally {
messageBuffer.release();
}
});
}
use of org.eclipse.milo.opcua.stack.core.types.structured.ServiceFault in project milo by eclipse.
the class OpcUaClient method maybeHandleServiceFault.
private void maybeHandleServiceFault(UaResponseMessage response, Throwable ex) {
if (faultListeners.isEmpty())
return;
if (ex != null) {
if (ex instanceof UaServiceFaultException) {
UaServiceFaultException faultException = (UaServiceFaultException) ex;
ServiceFault serviceFault = faultException.getServiceFault();
logger.debug("Notifying {} ServiceFaultListeners", faultListeners.size());
faultNotificationQueue.submit(() -> faultListeners.forEach(h -> h.onServiceFault(serviceFault)));
} else if (ex.getCause() instanceof UaServiceFaultException) {
UaServiceFaultException faultException = (UaServiceFaultException) ex.getCause();
ServiceFault serviceFault = faultException.getServiceFault();
logger.debug("Notifying {} ServiceFaultListeners", faultListeners.size());
faultNotificationQueue.submit(() -> faultListeners.forEach(h -> h.onServiceFault(serviceFault)));
}
}
}
use of org.eclipse.milo.opcua.stack.core.types.structured.ServiceFault in project milo by eclipse.
the class UascClientMessageHandler method onOpenSecureChannel.
private void onOpenSecureChannel(ChannelHandlerContext ctx, ByteBuf buffer) throws UaException {
if (secureChannelTimeout != null) {
if (secureChannelTimeout.cancel()) {
logger.debug("OpenSecureChannel timeout canceled");
secureChannelTimeout = null;
} else {
logger.warn("timed out waiting for secure channel");
handshakeFuture.completeExceptionally(new UaException(StatusCodes.Bad_Timeout, "timed out waiting for secure channel"));
ctx.close();
return;
}
}
// skip messageType, chunkType, messageSize, secureChannelId
buffer.skipBytes(3 + 1 + 4 + 4);
AsymmetricSecurityHeader securityHeader = AsymmetricSecurityHeader.decode(buffer, config.getEncodingLimits());
if (headerRef.compareAndSet(null, securityHeader)) {
// first time we've received the header; validate and verify the server certificate
CertificateValidator certificateValidator = config.getCertificateValidator();
SecurityPolicy securityPolicy = SecurityPolicy.fromUri(securityHeader.getSecurityPolicyUri());
if (securityPolicy != SecurityPolicy.None) {
ByteString serverCertificateBytes = securityHeader.getSenderCertificate();
List<X509Certificate> serverCertificateChain = CertificateUtil.decodeCertificates(serverCertificateBytes.bytesOrEmpty());
certificateValidator.validateCertificateChain(serverCertificateChain);
}
} else {
if (!securityHeader.equals(headerRef.get())) {
throw new UaException(StatusCodes.Bad_SecurityChecksFailed, "subsequent AsymmetricSecurityHeader did not match");
}
}
if (accumulateChunk(buffer)) {
final List<ByteBuf> buffersToDecode = chunkBuffers;
chunkBuffers = new ArrayList<>(maxChunkCount);
serializationQueue.decode((binaryDecoder, chunkDecoder) -> {
ByteBuf message;
try {
ChunkDecoder.DecodedMessage decodedMessage = chunkDecoder.decodeAsymmetric(secureChannel, buffersToDecode);
message = decodedMessage.getMessage();
} catch (MessageAbortException e) {
logger.warn("Received message abort chunk; error={}, reason={}", e.getStatusCode(), e.getMessage());
return;
} catch (MessageDecodeException e) {
logger.error("Error decoding asymmetric message", e);
handshakeFuture.completeExceptionally(e);
ctx.close();
return;
}
try {
UaResponseMessage response = (UaResponseMessage) binaryDecoder.setBuffer(message).readMessage(null);
StatusCode serviceResult = response.getResponseHeader().getServiceResult();
if (serviceResult.isGood()) {
OpenSecureChannelResponse oscr = (OpenSecureChannelResponse) response;
secureChannel.setChannelId(oscr.getSecurityToken().getChannelId().longValue());
logger.debug("Received OpenSecureChannelResponse.");
NonceUtil.validateNonce(oscr.getServerNonce(), secureChannel.getSecurityPolicy());
installSecurityToken(ctx, oscr);
handshakeFuture.complete(secureChannel);
} else {
ServiceFault serviceFault = (response instanceof ServiceFault) ? (ServiceFault) response : new ServiceFault(response.getResponseHeader());
handshakeFuture.completeExceptionally(new UaServiceFaultException(serviceFault));
ctx.close();
}
} catch (Throwable t) {
logger.error("Error decoding OpenSecureChannelResponse", t);
handshakeFuture.completeExceptionally(t);
ctx.close();
} finally {
message.release();
}
});
}
}
use of org.eclipse.milo.opcua.stack.core.types.structured.ServiceFault in project milo by eclipse.
the class UaStackClient method deliverResponse.
/**
* Complete {@code future} with {@code response} on the {@code deliveryQueue}.
* <p>
* This is done for two reasons:
* 1. the transport future is completed on its serialization queue thread, which we want to get off of ASAP.
* 2. the futures need to be completed serially, in the order received from the server.
*
* @param request the original {@link UaRequestMessage}.
* @param response the {@link UaResponseMessage}.
* @param future the {@link CompletableFuture} awaiting completion.
*/
private void deliverResponse(UaRequestMessage request, @Nullable UaResponseMessage response, @Nullable Throwable failure, CompletableFuture<UaResponseMessage> future) {
deliveryQueue.submit(() -> {
if (response != null) {
ResponseHeader header = response.getResponseHeader();
UInteger requestHandle = header.getRequestHandle();
if (header.getServiceResult().isGood()) {
future.complete(response);
} else {
ServiceFault serviceFault;
if (response instanceof ServiceFault) {
serviceFault = (ServiceFault) response;
} else {
serviceFault = new ServiceFault(header);
}
if (logger.isDebugEnabled()) {
logger.debug("Received ServiceFault request={} requestHandle={}, result={}", request.getClass().getSimpleName(), requestHandle, header.getServiceResult());
}
future.completeExceptionally(new UaServiceFaultException(serviceFault));
}
} else {
assert failure != null;
if (logger.isDebugEnabled()) {
logger.debug("sendRequest() failed, request={}, requestHandle={}", request.getClass().getSimpleName(), request.getRequestHeader().getRequestHandle(), failure);
}
future.completeExceptionally(failure);
}
});
}
use of org.eclipse.milo.opcua.stack.core.types.structured.ServiceFault in project milo by eclipse.
the class SessionFsmFactory method transferSubscriptions.
@SuppressWarnings("Duplicates")
private static CompletableFuture<Unit> transferSubscriptions(FsmContext<State, Event> ctx, OpcUaClient client, OpcUaSession session) {
UaStackClient stackClient = client.getStackClient();
OpcUaSubscriptionManager subscriptionManager = client.getSubscriptionManager();
ImmutableList<UaSubscription> subscriptions = subscriptionManager.getSubscriptions();
if (subscriptions.isEmpty()) {
return completedFuture(Unit.VALUE);
}
CompletableFuture<Unit> transferFuture = new CompletableFuture<>();
UInteger[] subscriptionIdsArray = subscriptions.stream().map(UaSubscription::getSubscriptionId).toArray(UInteger[]::new);
TransferSubscriptionsRequest request = new TransferSubscriptionsRequest(client.newRequestHeader(session.getAuthenticationToken()), subscriptionIdsArray, true);
LOGGER.debug("[{}] Sending TransferSubscriptionsRequest...", ctx.getInstanceId());
stackClient.sendRequest(request).thenApply(TransferSubscriptionsResponse.class::cast).whenComplete((tsr, ex) -> {
if (tsr != null) {
List<TransferResult> results = l(tsr.getResults());
LOGGER.debug("[{}] TransferSubscriptions supported: {}", ctx.getInstanceId(), tsr.getResponseHeader().getServiceResult());
if (LOGGER.isDebugEnabled()) {
try {
Stream<UInteger> subscriptionIds = subscriptions.stream().map(UaSubscription::getSubscriptionId);
Stream<StatusCode> statusCodes = results.stream().map(TransferResult::getStatusCode);
// noinspection UnstableApiUsage
String[] ss = Streams.zip(subscriptionIds, statusCodes, (i, s) -> String.format("id=%s/%s", i, StatusCodes.lookup(s.getValue()).map(sa -> sa[0]).orElse(s.toString()))).toArray(String[]::new);
LOGGER.debug("[{}] TransferSubscriptions results: {}", ctx.getInstanceId(), Arrays.toString(ss));
} catch (Throwable t) {
LOGGER.error("[{}] error logging TransferSubscription results", ctx.getInstanceId(), t);
}
}
client.getConfig().getExecutor().execute(() -> {
for (int i = 0; i < results.size(); i++) {
TransferResult result = results.get(i);
if (!result.getStatusCode().isGood()) {
UaSubscription subscription = subscriptions.get(i);
subscriptionManager.transferFailed(subscription.getSubscriptionId(), result.getStatusCode());
}
}
});
transferFuture.complete(Unit.VALUE);
} else {
StatusCode statusCode = UaException.extract(ex).map(UaException::getStatusCode).orElse(StatusCode.BAD);
LOGGER.debug("[{}] TransferSubscriptions not supported: {}", ctx.getInstanceId(), statusCode);
client.getConfig().getExecutor().execute(() -> {
// because the list from getSubscriptions() above is a copy.
for (UaSubscription subscription : subscriptions) {
subscriptionManager.transferFailed(subscription.getSubscriptionId(), statusCode);
}
});
// supported but server implementations interpret the spec differently.
if (statusCode.getValue() == StatusCodes.Bad_NotImplemented || statusCode.getValue() == StatusCodes.Bad_NotSupported || statusCode.getValue() == StatusCodes.Bad_OutOfService || statusCode.getValue() == StatusCodes.Bad_ServiceUnsupported) {
// One of the expected responses; continue moving through the FSM.
transferFuture.complete(Unit.VALUE);
} else {
// An unexpected response; complete exceptionally and start over.
// Subsequent runs through the FSM will not attempt transfer because
// transferFailed() has been called for all the existing subscriptions.
// This will prevent us from getting stuck in a "loop" attempting to
// reconnect to a defective server that responds with a channel-level
// Error message to subscription transfer requests instead of an
// application-level ServiceFault.
transferFuture.completeExceptionally(ex);
}
}
});
return transferFuture;
}
Aggregations