use of org.dcache.xrootd.util.ParseException in project dcache by dCache.
the class XrootdPoolRequestHandler method doOnOpen.
/**
* Obtains the right mover channel using an opaque token in the request. The mover channel is
* wrapped by a file descriptor. The file descriptor is stored for subsequent access.
* <p>
* In the case that this is a write request as destination in a third party copy, a third-party
* client is started. The client issues login, open and read requests to the source server, and
* writes the responses to the file descriptor.
* <p>
* The third-party client also sends a sync response back to the client when the transfer has
* completed.
*/
@Override
protected XrootdResponse<OpenRequest> doOnOpen(ChannelHandlerContext ctx, OpenRequest msg) throws XrootdException {
try {
Map<String, String> opaqueMap = getOpaqueMap(msg.getOpaque());
UUID uuid = getUuid(opaqueMap);
if (uuid == null) {
_log.info("Request to open {} contains no UUID.", msg.getPath());
throw new XrootdException(kXR_NotAuthorized, "Request lacks the " + UUID_PREFIX + " property.");
}
enforceClientTlsIfDestinationRequiresItForTpc(opaqueMap);
NettyTransferService<XrootdProtocolInfo>.NettyMoverChannel file = _server.openFile(uuid, false);
if (file == null) {
_log.info("No mover found for {} with UUID {}.", msg.getPath(), uuid);
return redirectToDoor(ctx, msg, () -> {
throw new XrootdException(kXR_NotAuthorized, UUID_PREFIX + " is no longer valid.");
});
}
/*
* Stop any timer in case this is a reconnect.
*/
_server.cancelReconnectTimeoutForMover(uuid);
_log.debug("doOnOpen, called cancel on reconnect timers for {}", uuid);
XrootdProtocolInfo protocolInfo = file.getProtocolInfo();
try {
FileDescriptor descriptor;
boolean isWrite = file.getIoMode().contains(StandardOpenOption.WRITE);
if (msg.isNew() && !isWrite) {
throw new XrootdException(kXR_FileNotOpen, "File exists.");
} else if (msg.isDelete() && !isWrite) {
throw new XrootdException(kXR_Unsupported, "File exists.");
/*
* Some clients express only kXR_delete when then intend to write
* so we need to consider delete as a write request here.
*/
} else if ((msg.isNew() || msg.isReadWrite() || msg.isDelete()) && isWrite) {
boolean posc = (msg.getOptions() & kXR_posc) == kXR_posc || protocolInfo.getFlags().contains(XrootdProtocolInfo.Flags.POSC);
if (opaqueMap.containsKey("tpc.src")) {
_log.debug("Request to open {} is as third-party destination.", msg);
XrootdTpcInfo tpcInfo = new XrootdTpcInfo(opaqueMap);
tpcInfo.setDelegatedProxy(protocolInfo.getDelegatedCredential());
tpcInfo.setUid(protocolInfo.getTpcUid());
tpcInfo.setGid(protocolInfo.getTpcGid());
descriptor = new TpcWriteDescriptor(file, posc, ctx, _server, opaqueMap.get("org.dcache.xrootd.client"), tpcInfo, tlsSessionInfo);
} else {
descriptor = new WriteDescriptor(file, posc);
}
} else {
descriptor = new ReadDescriptor(file);
}
FileStatus stat = msg.isRetStat() ? stat(file) : null;
int fd = addDescriptor(descriptor);
_redirectingDoor = protocolInfo.getDoorAddress();
file = null;
_hasOpenedFiles = true;
return new OpenResponse(msg, fd, null, null, stat);
} finally {
if (file != null) {
file.release();
}
}
} catch (ParseException e) {
throw new XrootdException(kXR_ArgInvalid, e.getMessage());
} catch (IOException e) {
throw new XrootdException(kXR_IOError, e.getMessage());
}
}
use of org.dcache.xrootd.util.ParseException in project xrootd4j by dCache.
the class XrootdAuthorizationHandler method authorize.
/**
* Performs authorization check and path mapping.
*
* @param ctx The ChannelHandlerContext
* @param request The xrootd message
* @param neededPerm The permission level that is required for the operation
* @param path The path to which access is requested
* @param opaque Opaque data sent with the request
* @return The path to which access is granted.
* @throws XrootdException if the request is denied
*/
private String authorize(ChannelHandlerContext ctx, XrootdRequest request, FilePerm neededPerm, String path, String opaque) throws XrootdException {
try {
InetSocketAddress destinationAddress = getDestinationAddress();
InetSocketAddress sourceAddress = getSourceAddress();
AuthorizationHandler handler = _authorizationFactory.createHandler(ctx);
/*
* check to see if we need TLS.
*/
if (handler instanceof RequiresTLS && !isTLSOn(ctx)) {
throw new XrootdException(kXR_Unsupported, "TLS is required " + "for " + _authorizationFactory.getName());
}
return handler.authorize(request.getSubject(), destinationAddress, sourceAddress, path, OpaqueStringParser.getOpaqueMap(opaque), request.getRequestId(), neededPerm);
} catch (GeneralSecurityException e) {
throw new XrootdException(kXR_NotAuthorized, "Authorization check failed: " + e.getMessage());
} catch (SecurityException e) {
throw new XrootdException(kXR_NotAuthorized, "Permission denied: " + e.getMessage());
} catch (ParseException e) {
throw new XrootdException(kXR_InvalidRequest, "Invalid opaque data: " + e.getMessage());
}
}
use of org.dcache.xrootd.util.ParseException in project xrootd4j by dCache.
the class AbstractClientRequestHandler method doOnAttnResponse.
protected void doOnAttnResponse(ChannelHandlerContext ctx, InboundAttnResponse response) throws XrootdException {
String message;
switch(response.getActnum()) {
case kXR_asyncab:
/*
* The client should immediately disconnect (i.e., close
* the socket connection) from the server and abort
* further execution.
*/
message = "Received abort from source server: " + response.getMessage();
throw new XrootdException(kXR_ServerError, message);
case kXR_asyncms:
/*
* The client should send the indicated message to the console.
* The parameters contain the message text.
*/
LOGGER.info("Received from source server: {}.", response.getMessage());
break;
case kXR_asyncgo:
/*
* The client may start sending requests. This code is sent to
* cancel the effects of a previous kXR_asyncwt code.
*
* Fall through to handle future cancellation.
*/
case kXR_asynresp:
/*
* The client should use the response data in the message to
* complete the request associated with the indicated streamid.
*
* For this to be valid, there has to be a waiting request
* for this pipeline. If future is null here, we skip it.
*/
synchronized (this) {
if (future != null) {
future.cancel(true);
doOnAsynResponse(ctx, response);
future = null;
}
}
break;
case kXR_asyncwt:
/*
* The client should hold off sending any new requests until the
* indicated amount of time has passed or until receiving a
* kXR_asyncgo action code.
*/
doOnWaitResponse(ctx, response);
break;
case kXR_asyncrd:
/*
* The client should immediately disconnect (i.e., close the
* socket connection) and reconnect to the indicated server.
*
* NOTE: without opaque data in the parameters, this redirect
* probably will not work here, but we will allow this to fail
* downstream.
*
* Fall through to redirect.
*/
case kXR_asyncdi:
/*
* The client should immediately disconnect
* (i.e., close the socket connection) from the server.
* Parameters indicate when a reconnect may be attempted.
*
* This is essentially a delayed redirect to the same
* endpoint.
*/
try {
doOnRedirectResponse(ctx, new InboundRedirectResponse(response));
} catch (ParseException e) {
throw new XrootdException(kXR_InvalidRequest, "bad redirect data from kXR_asyncdi");
}
break;
case kXR_asyncav:
/*
* The file or file(s) the client previously
* requested to be prepared are now available.
*
* We do not issue prepare requests. NR.
*/
case kXR_asynunav:
/*
* The file or file(s) the client previously requested to
* be prepared cannot be made available.
*
* We do not issue prepare requests. NR.
*/
throw new XrootdException(kXR_Unsupported, "tpc client does not support this option: " + response.getActnum());
default:
throw new XrootdException(kXR_ArgInvalid, "unrecognized kXR_attn action: " + response.getActnum());
}
}
use of org.dcache.xrootd.util.ParseException in project xrootd4j by dCache.
the class XrootdClientDecoder method decode.
@Override
protected void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) {
ChannelId id = ctx.channel().id();
int readable = in.readableBytes();
if (readable < SERVER_RESPONSE_LEN) {
return;
}
int pos = in.readerIndex();
int headerFrameLength = in.getInt(pos + 4);
if (headerFrameLength < 0) {
LOGGER.error("Decoder {}, channel {}: received illegal " + "frame length in " + "xrootd header: {}." + " Closing channel.", sourceUrn, id, headerFrameLength);
ctx.channel().close();
return;
}
int length = SERVER_RESPONSE_LEN + headerFrameLength;
if (readable < length) {
return;
}
ByteBuf frame = in.readSlice(length);
int requestId = client.getExpectedResponse();
try {
switch(frame.getUnsignedShort(2)) {
case kXR_error:
LOGGER.debug("Decoder {}, channel {}: adding error response.", sourceUrn, id);
out.add(new InboundErrorResponse(frame));
return;
case kXR_wait:
LOGGER.debug("Decoder {}, channel {}: adding wait response.", sourceUrn, id);
out.add(new InboundWaitResponse(frame, requestId));
return;
case kXR_waitresp:
LOGGER.debug("Decoder {}, channel {}: adding waitresp response.", sourceUrn, id);
out.add(new InboundWaitRespResponse(frame, requestId));
return;
case kXR_redirect:
LOGGER.debug("Decoder {}, channel {}: adding redirect response.", sourceUrn, id);
out.add(new InboundRedirectResponse(frame, requestId));
return;
case kXR_attn:
LOGGER.debug("Decoder {}, channel {}: adding attn response.", sourceUrn, id);
out.add(new InboundAttnResponse(frame, requestId));
return;
}
switch(requestId) {
case kXR_handshake:
LOGGER.debug("Decoder {}, channel {}: adding handshake response.", sourceUrn, id);
out.add(new InboundHandshakeResponse(frame));
break;
case kXR_protocol:
LOGGER.debug("Decoder {}, channel {}: adding protocol response.", sourceUrn, id);
out.add(new InboundProtocolResponse(frame));
break;
case kXR_login:
LOGGER.debug("Decoder {}, channel {}: adding login response.", sourceUrn, id);
out.add(new InboundLoginResponse(frame));
break;
case kXR_auth:
LOGGER.debug("Decoder {}, channel {}: adding authentication response.", sourceUrn, id);
out.add(new InboundAuthenticationResponse(frame));
break;
case kXR_open:
LOGGER.debug("Decoder {}, channel {}: adding open response.", sourceUrn, id);
out.add(new InboundOpenReadOnlyResponse(frame));
break;
case kXR_read:
LOGGER.debug("Decoder {}, channel {}: adding read response.", sourceUrn, id);
out.add(new InboundReadResponse(frame));
break;
case kXR_query:
LOGGER.debug("Decoder {}, channel {}: adding query response.", sourceUrn, id);
out.add(new InboundChecksumResponse(frame));
break;
case kXR_close:
LOGGER.debug("Decoder {}, channel {}: adding close response.", sourceUrn, id);
out.add(new InboundCloseResponse(frame));
break;
case kXR_endsess:
LOGGER.debug("Decoder {}, channel {}: adding endsess response.", sourceUrn, id);
out.add(new InboundEndSessionResponse(frame));
break;
default:
LOGGER.debug("Decoder {}, channel {}, received incorrect " + "response of request type {}.", sourceUrn, id, requestId);
throw new XrootdException(kXR_error, "received incorrect response type.");
}
} catch (ParseException | XrootdException e) {
LOGGER.error("Decoder {}, channel {}: error for request type {}: {}. " + "Closing channel.", requestId, id, e.getMessage());
client.setError(e);
client.shutDown(ctx);
}
}
use of org.dcache.xrootd.util.ParseException in project xrootd4j by dCache.
the class InboundRedirectResponse method parseRedirectString.
private void parseRedirectString(String redirect) throws ParseException {
if (port == -1) {
try {
url = new URL(redirect);
} catch (MalformedURLException e) {
throw new ParseException("redirect : " + e.getMessage());
}
} else {
int index = redirect.indexOf("?");
if (index == -1) {
host = redirect;
} else {
host = redirect.substring(0, index);
redirect = redirect.substring(index);
while (redirect.startsWith("?")) {
redirect = redirect.substring(1);
}
if (redirect.contains("=")) {
String[] parts = redirect.split("[?]");
opaque = parts[0];
if (parts.length > 1) {
token = parts[1];
}
} else {
opaque = "";
token = redirect;
}
}
}
}
Aggregations