Search in sources :

Example 1 with FilePerm

use of org.dcache.xrootd.protocol.XrootdProtocol.FilePerm in project dcache by dCache.

the class XrootdRedirectHandler method doOnOpen.

/**
 * For client-server read and write, the open, if successful, will always result in a redirect
 * response to the proper pool; hence no subsequent requests like sync, read, write or close are
 * expected at the door.
 * <p>
 * For third-party copy where dCache is the source, the interactions are as follows:
 * <p>
 * 1.  The client opens the file to check availability (the 'placement' stage).  An OK response
 * is followed by the client closing the file. 2.  The client opens the file again with
 * rendezvous metadata.  The client will close the file only when notified by the destination
 * server that the transfer has completed. 3.  The destination server will open the file for the
 * actual read.
 * <p>
 * The order of 2, 3 is not deterministic; hence the response here must provide for the
 * possibility that the destination server attempts an open before the client specifies a
 * time-to-live on the rendezvous point.
 * <p>
 * The strategy adopted is therefore as follows:  response to (1) is simply to check file
 * permissions.  No metadata is generated and a "dummy" file handle is returned.  For 2 and 3,
 * whichever occurs first will cause a metadata object to be stored.  If the destination server
 * open occurs first, a wait response will tell the server to try again in a maximum of 3
 * seconds; otherwise, if the request matches and occurs within the ttl, the mover will be
 * started and the destination redirected to the pool. Response to the client will carry a file
 * handle but will not actually open a mover.  The close from the client is handled at the door
 * by removing the rendezvous information.
 * <p>
 * Third-party copy where dCache is the destination should proceed with the usual upload
 * transfer creation, but when the client is redirected to the pool and calls kXR_open there, a
 * third-party client will be started which does read requests from the source and then writes
 * the data to the mover channel.
 * <p>
 * NOTE:  with the changed TPC Lite protocol, the client is not required to open the source
 * again during the copy phase (2) if delegation is being used.
 */
@Override
protected XrootdResponse<OpenRequest> doOnOpen(ChannelHandlerContext ctx, OpenRequest req) {
    /*
         * TODO
         *
         * We ought to process this asynchronously to not block the calling thread during
         * staging or queuing. We should also switch to an asynchronous reply model if
         * the request is nearline or is queued on a pool. The naive approach to always
         * use an asynchronous reply model doesn't work because the xrootd 3.x client
         * introduces an artificial 1 second delay when processing such a response.
         */
    InetSocketAddress localAddress = getDestinationAddress();
    InetSocketAddress remoteAddress = getSourceAddress();
    LoginSessionInfo loginSessionInfo = sessionInfo();
    Map<String, String> opaque;
    try {
        opaque = OpaqueStringParser.getOpaqueMap(req.getOpaque());
        if (opaque.isEmpty()) {
            /*
                 * create a new HashMap as empty opaque map is immutable
                 */
            opaque = new HashMap<>();
        }
    } catch (ParseException e) {
        _log.warn("Ignoring malformed open opaque {}: {}", req.getOpaque(), e.getMessage());
        opaque = new HashMap<>();
    }
    try {
        FsPath path = createFullPath(req.getPath());
        XrootdResponse response = conditionallyHandleThirdPartyRequest(req, loginSessionInfo, opaque, path, remoteAddress.getHostName());
        if (response != null) {
            return response;
        }
        FilePerm neededPerm = req.getRequiredPermission();
        _log.info("Opening {} for {}", req.getPath(), neededPerm.xmlText());
        if (_log.isDebugEnabled()) {
            logDebugOnOpen(req);
        }
        String ioQueue = appSpecificQueue(req);
        Long size = null;
        try {
            String value = opaque.get("oss.asize");
            if (value != null) {
                size = Long.valueOf(value);
            }
        } catch (NumberFormatException exception) {
            _log.warn("Ignoring malformed oss.asize: {}", exception.getMessage());
        }
        _log.info("OPAQUE : {}", opaque);
        Set<String> triedHosts = extractTriedHosts(opaque);
        UUID uuid = UUID.randomUUID();
        opaque.put(UUID_PREFIX, uuid.toString());
        /*
             *  In case this is a third-party open as destination,
             *  pass the client information to the pool.
             */
        opaque.put("org.dcache.xrootd.client", getTpcClientId(req.getSession()));
        String opaqueString = OpaqueStringParser.buildOpaqueString(opaque);
        /*
             * Interact with core dCache to open the requested file.
             */
        XrootdTransfer transfer;
        if (neededPerm == FilePerm.WRITE) {
            /**
             *  boolean createDir = req.isMkPath() has
             *  been changed to default to true
             *  so as to conform to the general expectations that this
             *  behavior should not depend on the client.
             */
            boolean overwrite = req.isDelete() && !req.isNew();
            boolean persistOnSuccessfulClose = (req.getOptions() & XrootdProtocol.kXR_posc) == XrootdProtocol.kXR_posc;
            // TODO: replace with req.isPersistOnSuccessfulClose() with the latest xrootd4j
            transfer = _door.write(remoteAddress, path, triedHosts, ioQueue, uuid, true, overwrite, size, loginSessionInfo.getMaximumUploadSize(), localAddress, loginSessionInfo.getSubject(), loginSessionInfo.getRestriction(), persistOnSuccessfulClose, ((loginSessionInfo.isLoggedIn()) ? loginSessionInfo.getUserRootPath() : _rootPath), req.getSession().getDelegatedCredential(), opaque);
        } else {
            /*
                 * If this is a tpc transfer, then dCache is source here.
                 *
                 * Since we accept (from the destination server) any
                 * valid form of authentication, but without requiring
                 * the associated user to be mapped, we can override
                 * file permission restrictions (since we possess the
                 * 'token' rendezvous key, and the client file permissions
                 * have been checked during its open request).
                 */
            Subject subject;
            if (opaque.get("tpc.key") == null) {
                subject = loginSessionInfo.getSubject();
            } else {
                subject = Subjects.ROOT;
            }
            transfer = _door.read(remoteAddress, path, triedHosts, ioQueue, uuid, localAddress, subject, loginSessionInfo.getRestriction(), opaque);
            /*
                 * Again, if this is a tpc transfer, then dCache is source here.
                 * The transfer is initiated by the destination server
                 * (= current session).  However, we wish the doorinfo
                 * client in billing to reflect the original user connection,
                 * so we overwrite the transfer client address, which
                 * is unused by the mover.
                 */
            String client = opaque.get("tpc.org");
            if (client != null) {
                int index = client.indexOf("@");
                if (index != -1 && index < client.length() - 1) {
                    client = client.substring(index + 1);
                    transfer.setClientAddress(new InetSocketAddress(client, 0));
                }
            }
        }
        /*
             * ok, open was successful
             */
        InetSocketAddress address = transfer.getRedirect();
        /*
             *  Do not use the IP address as host name, as this will block
             *  TLS from working.
             *
             *  According to https://tools.ietf.org/html/rfc5280#section-4.2.1.6
             *  an IP is required to be in the list of Subject Alternative Names
             *  in the host certificate, but these are rarely added in practice.
             *  TLS enforces the RFC and this is a workaround.
             */
        String host = address.getHostName();
        if (InetAddresses.isInetAddress(host)) {
            _log.warn("Unable to resolve IP address {} " + "to a canonical name", host);
        }
        _log.info("Redirecting to {}, {}", host, address);
        return new RedirectResponse<>(req, host, address.getPort(), opaqueString, "");
    } catch (ParseException e) {
        return withError(req, kXR_ArgInvalid, "Path arguments do not parse");
    } catch (FileNotFoundCacheException e) {
        return withError(req, xrootdErrorCode(e.getRc()), "No such file");
    } catch (FileExistsCacheException e) {
        return withError(req, kXR_NotAuthorized, "File already exists");
    } catch (TimeoutCacheException e) {
        return withError(req, xrootdErrorCode(e.getRc()), "Internal timeout");
    } catch (PermissionDeniedCacheException e) {
        return withError(req, xrootdErrorCode(e.getRc()), e.getMessage());
    } catch (FileIsNewCacheException e) {
        return withError(req, xrootdErrorCode(e.getRc()), "File is locked by upload");
    } catch (NotFileCacheException e) {
        return withError(req, xrootdErrorCode(e.getRc()), "Not a file");
    } catch (CacheException e) {
        return withError(req, xrootdErrorCode(e.getRc()), String.format("Failed to open file (%s [%d])", e.getMessage(), e.getRc()));
    } catch (InterruptedException e) {
        /* Interrupt may be caused by cell shutdown or client
             * disconnect.  If the client disconnected, then the error
             * message will never reach the client, so saying that the
             * server shut down is okay.
             */
        return withError(req, kXR_ServerError, "Server shutdown");
    } catch (XrootdException e) {
        return withError(req, e.getError(), e.getMessage());
    }
}
Also used : HashMap(java.util.HashMap) FileIsNewCacheException(diskCacheV111.util.FileIsNewCacheException) FileExistsCacheException(diskCacheV111.util.FileExistsCacheException) FileNotFoundCacheException(diskCacheV111.util.FileNotFoundCacheException) NotFileCacheException(diskCacheV111.util.NotFileCacheException) TimeoutCacheException(diskCacheV111.util.TimeoutCacheException) CacheException(diskCacheV111.util.CacheException) PermissionDeniedCacheException(diskCacheV111.util.PermissionDeniedCacheException) InetSocketAddress(java.net.InetSocketAddress) XrootdResponse(org.dcache.xrootd.protocol.messages.XrootdResponse) FileIsNewCacheException(diskCacheV111.util.FileIsNewCacheException) UUID(java.util.UUID) XrootdException(org.dcache.xrootd.core.XrootdException) FsPath(diskCacheV111.util.FsPath) RedirectResponse(org.dcache.xrootd.protocol.messages.RedirectResponse) FilePerm(org.dcache.xrootd.protocol.XrootdProtocol.FilePerm) Subject(javax.security.auth.Subject) NotFileCacheException(diskCacheV111.util.NotFileCacheException) PermissionDeniedCacheException(diskCacheV111.util.PermissionDeniedCacheException) OptionalLong(java.util.OptionalLong) FileNotFoundCacheException(diskCacheV111.util.FileNotFoundCacheException) ParseException(org.dcache.xrootd.util.ParseException) FileExistsCacheException(diskCacheV111.util.FileExistsCacheException) TimeoutCacheException(diskCacheV111.util.TimeoutCacheException)

Aggregations

CacheException (diskCacheV111.util.CacheException)1 FileExistsCacheException (diskCacheV111.util.FileExistsCacheException)1 FileIsNewCacheException (diskCacheV111.util.FileIsNewCacheException)1 FileNotFoundCacheException (diskCacheV111.util.FileNotFoundCacheException)1 FsPath (diskCacheV111.util.FsPath)1 NotFileCacheException (diskCacheV111.util.NotFileCacheException)1 PermissionDeniedCacheException (diskCacheV111.util.PermissionDeniedCacheException)1 TimeoutCacheException (diskCacheV111.util.TimeoutCacheException)1 InetSocketAddress (java.net.InetSocketAddress)1 HashMap (java.util.HashMap)1 OptionalLong (java.util.OptionalLong)1 UUID (java.util.UUID)1 Subject (javax.security.auth.Subject)1 XrootdException (org.dcache.xrootd.core.XrootdException)1 FilePerm (org.dcache.xrootd.protocol.XrootdProtocol.FilePerm)1 RedirectResponse (org.dcache.xrootd.protocol.messages.RedirectResponse)1 XrootdResponse (org.dcache.xrootd.protocol.messages.XrootdResponse)1 ParseException (org.dcache.xrootd.util.ParseException)1