Skip to content

Commit

Permalink
nfs41: add possibility to specify server implementation details
Browse files Browse the repository at this point in the history
Motivation:
The EXCHANGE_ID operation allows server to expose his implementation
information. However this information in nfs4j is hardcoded and can't be
used by implementers.

Modification:
Update NFSServerV41#Builder to allow custom server implementations.

Result:
a possibility to specify server implementation details.

Acked-by: Paul Millar
Target: master
  • Loading branch information
kofemann committed May 9, 2023
1 parent a7cc8b4 commit 908045a
Show file tree
Hide file tree
Showing 9 changed files with 215 additions and 61 deletions.
69 changes: 69 additions & 0 deletions core/src/main/java/org/dcache/nfs/util/Misc.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
/*
* Copyright (c) 2009 - 2023 Deutsches Elektronen-Synchroton,
* Member of the Helmholtz Association, (DESY), HAMBURG, GERMANY
*
* This library is free software; you can redistribute it and/or modify
* it under the terms of the GNU Library General Public License as
* published by the Free Software Foundation; either version 2 of the
* License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this program (see the file COPYING.LIB for more
* details); if not, write to the Free Software Foundation, Inc.,
* 675 Mass Ave, Cambridge, MA 02139, USA.
*/
package org.dcache.nfs.util;

import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.security.CodeSource;
import java.security.ProtectionDomain;
import java.time.Instant;
import java.time.format.DateTimeParseException;
import java.util.Optional;
import java.util.jar.Attributes;
import java.util.jar.JarInputStream;
import java.util.jar.Manifest;

public class Misc {

private Misc() {}

/**
* Get package build time. This method uses {@code Build-Time} attribute in the
* jar Manifest file.
* @return optional instant of package build time.
*/
public static Optional<Instant> getBuildTime() {

try {

ProtectionDomain pd = Misc.class.getProtectionDomain();
CodeSource cs = pd.getCodeSource();
URL u = cs.getLocation();

InputStream is = u.openStream();
JarInputStream jis = new JarInputStream(is);
Manifest m = jis.getManifest();

if (m != null) {
Attributes as = m.getMainAttributes();
String buildTime = as.getValue("Build-Time");
if (buildTime != null) {
return Optional.of(Instant.parse(buildTime));
}
}

} catch (IOException | DateTimeParseException e) {
// bad luck
}

return Optional.empty();
}
}
21 changes: 16 additions & 5 deletions core/src/main/java/org/dcache/nfs/v4/CompoundContext.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2009 - 2020 Deutsches Elektronen-Synchroton,
* Copyright (c) 2009 - 2023 Deutsches Elektronen-Synchroton,
* Member of the Helmholtz Association, (DESY), HAMBURG, GERMANY
*
* This library is free software; you can redistribute it and/or modify
Expand All @@ -25,7 +25,12 @@
import com.sun.security.auth.UnixNumericUserPrincipal;
import org.dcache.nfs.ChimeraNFSException;
import org.dcache.nfs.ExportTable;
import org.dcache.nfs.v4.xdr.nfs_impl_id4;
import org.dcache.nfs.v4.xdr.nfs_resop4;
import org.dcache.nfs.v4.xdr.server_owner4;
import org.dcache.nfs.v4.xdr.stateid4;
import org.dcache.nfs.v4.xdr.uint64_t;
import org.dcache.nfs.v4.xdr.verifier4;
import org.dcache.oncrpc4j.rpc.RpcCall;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
Expand All @@ -39,10 +44,6 @@
import org.dcache.nfs.status.NoFileHandleException;
import org.dcache.nfs.status.RestoreFhException;
import org.dcache.nfs.v4.nlm.LockManager;
import org.dcache.nfs.v4.xdr.server_owner4;
import org.dcache.nfs.v4.xdr.stateid4;
import org.dcache.nfs.v4.xdr.uint64_t;
import org.dcache.nfs.v4.xdr.verifier4;
import org.dcache.nfs.vfs.VirtualFileSystem;
import org.dcache.oncrpc4j.rpc.net.InetSocketAddresses;
import org.dcache.oncrpc4j.rpc.RpcAuthType;
Expand Down Expand Up @@ -96,6 +97,8 @@ public boolean equals(Object obj) {
private final int _exchangeIdFlags;
private final verifier4 _rebootVerifier;

private final nfs_impl_id4 _implId;

/**
* Create context of COUMPOUND request.
*
Expand All @@ -114,6 +117,7 @@ public CompoundContext(CompoundContextBuilder builder) {
_principal = principalOf(_callInfo);
_exchangeIdFlags = builder.getExchangeIdFlags();
_rebootVerifier = builder.getRebootVerifier();
_implId = builder.getImplementationId();
}

public RpcCall getRpcCall() {
Expand Down Expand Up @@ -354,4 +358,11 @@ public InetSocketAddress getLocalSocketAddress() {
public verifier4 getRebootVerifier() {
return _rebootVerifier;
}

/**
* Return server Implementation ID.
*/
public nfs_impl_id4 getImplementationId() {
return _implId;
}
}
15 changes: 13 additions & 2 deletions core/src/main/java/org/dcache/nfs/v4/CompoundContextBuilder.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2009 - 2020 Deutsches Elektronen-Synchroton,
* Copyright (c) 2009 - 2023 Deutsches Elektronen-Synchroton,
* Member of the Helmholtz Association, (DESY), HAMBURG, GERMANY
*
* This library is free software; you can redistribute it and/or modify
Expand All @@ -19,10 +19,10 @@
*/
package org.dcache.nfs.v4;

import org.dcache.nfs.ExportFile;
import org.dcache.nfs.ExportTable;
import org.dcache.nfs.v4.nlm.LockManager;
import org.dcache.nfs.v4.xdr.nfs4_prot;
import org.dcache.nfs.v4.xdr.nfs_impl_id4;
import org.dcache.nfs.vfs.VirtualFileSystem;
import org.dcache.nfs.v4.xdr.verifier4;
import org.dcache.oncrpc4j.rpc.RpcCall;
Expand All @@ -41,6 +41,8 @@ public class CompoundContextBuilder {
private int exchangeIdFlags = nfs4_prot.EXCHGID4_FLAG_USE_NON_PNFS;
private verifier4 rebootVerifier;

private nfs_impl_id4 implId;

public CompoundContextBuilder withCall(RpcCall call) {
this.call = call;
return this;
Expand Down Expand Up @@ -76,6 +78,11 @@ public CompoundContextBuilder withLockManager(LockManager lm) {
return this;
}

public CompoundContextBuilder withImplementationId(nfs_impl_id4 impId) {
this.implId = impId;
return this;
}

public LockManager getLm() {
return lm;
}
Expand Down Expand Up @@ -104,6 +111,10 @@ public ExportTable getExportTable() {
return exportTable;
}

public nfs_impl_id4 getImplementationId() {
return implId;
}

public CompoundContext build() {

requireNonNull(call);
Expand Down
42 changes: 34 additions & 8 deletions core/src/main/java/org/dcache/nfs/v4/NFSServerV41.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2009 - 2020 Deutsches Elektronen-Synchroton,
* Copyright (c) 2009 - 2023 Deutsches Elektronen-Synchroton,
* Member of the Helmholtz Association, (DESY), HAMBURG, GERMANY
*
* This library is free software; you can redistribute it and/or modify
Expand All @@ -22,21 +22,18 @@
import org.dcache.nfs.ChimeraNFSException;
import org.dcache.nfs.ExportTable;
import org.dcache.nfs.ExportFile;
import org.dcache.nfs.v4.xdr.COMPOUND4args;
import org.dcache.nfs.v4.xdr.COMPOUND4res;
import org.dcache.nfs.v4.xdr.nfs4_prot_NFS4_PROGRAM_ServerStub;
import org.dcache.nfs.v4.xdr.nfs_argop4;
import org.dcache.nfs.v4.xdr.nfs_resop4;
import org.dcache.nfs.v4.xdr.*;
import org.dcache.nfs.nfsstat;
import org.dcache.oncrpc4j.rpc.RpcCall;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.slf4j.MDC;

import java.time.Instant;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import org.dcache.nfs.v4.xdr.nfs_opnum4;

import org.dcache.nfs.vfs.PseudoFs;
import org.dcache.nfs.vfs.VirtualFileSystem;
import org.dcache.nfs.status.MinorVersMismatchException;
Expand All @@ -48,7 +45,6 @@
import org.dcache.nfs.status.TooManyOpsException;
import org.dcache.nfs.v4.nlm.LockManager;
import org.dcache.nfs.v4.nlm.SimpleLm;
import org.dcache.nfs.v4.xdr.verifier4;

public class NFSServerV41 extends nfs4_prot_NFS4_PROGRAM_ServerStub {

Expand All @@ -60,6 +56,8 @@ public class NFSServerV41 extends nfs4_prot_NFS4_PROGRAM_ServerStub {
private final NFSv41DeviceManager _deviceManager;
private final NFSv4StateHandler _statHandler;
private final LockManager _nlm;
private final nfs_impl_id4 _implementationId;

/**
* Verifier to indicate client that server is rebooted. Current currentTimeMillis
* is good enough, unless server reboots within a millisecond.
Expand All @@ -73,6 +71,12 @@ private NFSServerV41(Builder builder) {
_operationExecutor = builder.operationExecutor;
_nlm = builder.nlm == null ? new SimpleLm() : builder.nlm;
_statHandler = builder.stateHandler == null ? new NFSv4StateHandler() : builder.stateHandler;

_implementationId = new nfs_impl_id4();
_implementationId.nii_date = new nfstime4(builder.implementationDate.toEpochMilli());
_implementationId.nii_domain = new utf8str_cis(builder.implementationDomain);
_implementationId.nii_name = new utf8str_cs(builder.implementationName);

}

@Deprecated
Expand All @@ -86,6 +90,11 @@ public NFSServerV41(OperationExecutor operationExecutor,
_operationExecutor = operationExecutor;
_nlm = new SimpleLm();
_statHandler = new NFSv4StateHandler();

_implementationId = new nfs_impl_id4();
_implementationId.nii_date = new nfstime4(NFSv4Defaults.NFS4_IMPLEMENTATION_DATE);
_implementationId.nii_domain = new utf8str_cis(NFSv4Defaults.NFS4_IMPLEMENTATION_DOMAIN);
_implementationId.nii_name = new utf8str_cs(NFSv4Defaults.NFS4_IMPLEMENTATION_ID);
}

@Override
Expand Down Expand Up @@ -136,6 +145,7 @@ public COMPOUND4res NFSPROC4_COMPOUND_4(RpcCall call$, COMPOUND4args arg1) {
.withLockManager(_nlm)
.withExportTable(_exportTable)
.withRebootVerifier(_rebootVerifier)
.withImplementationId(_implementationId)
.withCall(call$);

if (_deviceManager != null) {
Expand Down Expand Up @@ -291,6 +301,9 @@ public static class Builder {
private ExportTable exportTable;
private LockManager nlm;
private NFSv4StateHandler stateHandler;
private String implementationName = NFSv4Defaults.NFS4_IMPLEMENTATION_ID;
private String implementationDomain = NFSv4Defaults.NFS4_IMPLEMENTATION_DOMAIN;
private Instant implementationDate = NFSv4Defaults.NFS4_IMPLEMENTATION_DATE;

public Builder withDeviceManager(NFSv41DeviceManager deviceManager) {
this.deviceManager = deviceManager;
Expand All @@ -317,6 +330,19 @@ public Builder withExportTable(ExportTable exportTable) {
return this;
}

public Builder withImplementationName(String implementationName) {
this.implementationName = implementationName;
return this;
}

public Builder withImplementationDomain(String implementationDomain) {
this.implementationDomain = implementationDomain;
return this;
}
public Builder withImplementationDate(Instant implementationDate) {
this.implementationDate = implementationDate;
return this;
}
/**
* @deprecated Use {@link #withExportTable}
*/
Expand Down
9 changes: 7 additions & 2 deletions core/src/main/java/org/dcache/nfs/v4/NFSv4Defaults.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2009 - 2014 Deutsches Elektronen-Synchroton,
* Copyright (c) 2009 - 2023 Deutsches Elektronen-Synchroton,
* Member of the Helmholtz Association, (DESY), HAMBURG, GERMANY
*
* This library is free software; you can redistribute it and/or modify
Expand All @@ -19,6 +19,10 @@
*/
package org.dcache.nfs.v4;

import org.dcache.nfs.util.Misc;

import java.time.Instant;

public interface NFSv4Defaults {

public static final int NFS4_LEASE_TIME = 90;
Expand Down Expand Up @@ -54,7 +58,7 @@ public interface NFSv4Defaults {
/**
* NFSv4.1 implementation date
*/
public final static long NFS4_IMPLEMENTATION_DATE = System.currentTimeMillis();
public final static Instant NFS4_IMPLEMENTATION_DATE = Misc.getBuildTime().orElse(Instant.now());

/**
* Maximal number of operations in a compound call
Expand All @@ -65,4 +69,5 @@ public interface NFSv4Defaults {
* Maximal number of session slots
*/
public final static int NFS4_MAX_SESSION_SLOTS = 16;

}
41 changes: 2 additions & 39 deletions core/src/main/java/org/dcache/nfs/v4/OperationEXCHANGE_ID.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2009 - 2017 Deutsches Elektronen-Synchroton,
* Copyright (c) 2009 - 2023 Deutsches Elektronen-Synchroton,
* Member of the Helmholtz Association, (DESY), HAMBURG, GERMANY
*
* This library is free software; you can redistribute it and/or modify
Expand Down Expand Up @@ -79,40 +79,6 @@ public class OperationEXCHANGE_ID extends AbstractNFSv4Operation {
| nfs4_prot.EXCHGID4_FLAG_UPD_CONFIRMED_REC_A
| nfs4_prot.EXCHGID4_FLAG_CONFIRMED_R);

/**
* compile time
*/
private static long COMPILE_TIME = 0;

static {
/*
* get 'Build-Time' attribute from jar file manifest ( if available )
*/
try {

ProtectionDomain pd = OperationEXCHANGE_ID.class.getProtectionDomain();
CodeSource cs = pd.getCodeSource();
URL u = cs.getLocation();

InputStream is = u.openStream();
JarInputStream jis = new JarInputStream(is);
Manifest m = jis.getManifest();

if (m != null) {
Attributes as = m.getMainAttributes();
String buildTime = as.getValue("Build-Time");
if( buildTime != null ) {
Instant dateTime = Instant.parse(buildTime);
COMPILE_TIME = dateTime.toEpochMilli();
}
}

}catch(IOException | DateTimeParseException e) {
_log.warn("Failed to get compile time: {}", e.getMessage());
// bad luck
}
}

public OperationEXCHANGE_ID(nfs_argop4 args) {
super(args, nfs_opnum4.OP_EXCHANGE_ID);
}
Expand Down Expand Up @@ -264,10 +230,7 @@ public void process(CompoundContext context, nfs_resop4 result) throws ChimeraNF
res.eir_resok4.eir_server_scope = serverIdProvider.getScope();

res.eir_resok4.eir_server_impl_id = new nfs_impl_id4[1];
res.eir_resok4.eir_server_impl_id[0] = new nfs_impl_id4();
res.eir_resok4.eir_server_impl_id[0].nii_domain = new utf8str_cis(NFS4_IMPLEMENTATION_DOMAIN);
res.eir_resok4.eir_server_impl_id[0].nii_name = new utf8str_cs(NFS4_IMPLEMENTATION_ID);
res.eir_resok4.eir_server_impl_id[0].nii_date = new nfstime4(COMPILE_TIME);
res.eir_resok4.eir_server_impl_id[0] = context.getImplementationId();

res.eir_resok4.eir_state_protect = new state_protect4_r();
res.eir_resok4.eir_state_protect.spr_how = state_protect_how4.SP4_NONE;
Expand Down
Loading

0 comments on commit 908045a

Please sign in to comment.