/*
* Copyright (c) Daniel Reichhard, daniel.reichhard@gmail.com
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by Daniel Reichhard
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
*/
package ejip.nfs;
import joprt.RtThread;
import com.jopdesign.sys.Const;
import ejip.Ejip;
import ejip.Ip;
import ejip.LinkLayer;
import ejip.Net;
import ejip.Packet;
import ejip.Slip;
import ejip.Udp;
import ejip.UdpHandler;
//import ejip.nfs.Nfs;
import ejip.nfs.NfsConst;
import ejip.nfs.Rpc;
import ejip.nfs.Xdr;
import ejip.nfs.Mount;
import ejip.nfs.datastructs.*;
import util.Serial;
import util.Timer;
public class NfsClient {
public static final int ACTION_QUERY_PORT_MAPPER_FOR_MOUNT = 0;
public static final int ACTION_QUERY_PORT_MAPPER_FOR_NFS = 1;
public static final int ACTION_QUERY_PORT_MAPPER_FOR_NLM = 2;
public static final int ACTION_CALL_MOUNT_NULL = 5;
public static final int ACTION_CALL_GET_EXPORTS = 6;
public static final int ACTION_CALL_DUMP = 7;
public static final int ACTION_CALL_NFS_NULL = 11;
public static final int ACTION_CALL_NFS_LOOKUP = 12;
public static final int MAX_EXPORTS = 5;
public static final int MAX_MOUNTS = 5;
public static final int MAX_GROUPS = 4; //multiplies with MAX_EXPORTS!
public static final int MAX_PACKETS = 8;
static final int MAX_PACKET_SIZE = 1500;
public static final int MAX_MSG_SIZE = MAX_PACKET_SIZE;
public static final int PACKET_TIMEOUT = 10000;
public UdpHandlerImpl uClient = new UdpHandlerImpl(this);
public Mount mount = new Mount(NfsConst.MOUNT_PROGRAM, NfsConst.MOUNT_VERSION, this);
public Nfs nfs = new Nfs(NfsConst.NFS_PROGRAM, NfsConst.NFS_VERSION, this);
public int xid = 0;
public int prog = NfsConst.NFS_PROGRAM;
public int vers = NfsConst.NFS_VERSION;
public int proc = 0;
public int portmapperPort = 111; //portmapper
public int destIP = 0;
public int ownIP = 0;
public StringBuffer hostname;
public Ejip ejip = new Ejip(MAX_PACKETS, MAX_PACKET_SIZE);
public Net net = new Net(ejip);
public Serial ser = new Serial(Const.IO_UART_BG_MODEM_BASE);
public LinkLayer ipLink;
public Packet p;
public StringBuffer messageBuffer = new StringBuffer();
public Callbackable caller;
public int hid = 0;
class WaitList {
public int xid;
public int action;
public int tstamp;
public int service;
public ResultType dataStruct;
}
WaitList[] waitList = new WaitList[MAX_PACKETS];
protected GetAttr3Res getAttrRes;
/**
* constructor
* @param myIP the IP address of the JOP Client
* @param destinationIP the IP of the RPC server
* @param portmapperPort the port on which the Portmapper is listening
* @param caller an instance implementing the Runnable interface
* @param myHostName the Hostname of the JOP Client
*/
public NfsClient(int myIP, int destinationIP, int portmapperPort, StringBuffer myHostname, Callbackable caller) {
//periode: 1000000 / ((115200 / 10 * 8) / 8) * 50 = 4340
new RtThread(10, 4400) { //TODO: fragen warum so große periode auch funktioniert
public void run() {
for (;;) {
waitForNextPeriod();
ser.loop();
}
}
};
new RtThread(9, 10000) {
public void run() {
for (;;) {
waitForNextPeriod();
ipLink.run();
Timer.wd();
}
}
};
new RtThread(7, 10000) {
public void run() {
for (;;) {
waitForNextPeriod();
net.run();
}
}
};
for (int i = 0; i < waitList.length; i++) {
waitList[i] = new WaitList();
}
destIP = destinationIP;
ownIP = myIP;
hostname = myHostname;
this.portmapperPort = portmapperPort;
ipLink = new Slip(ejip, ser, ownIP);
this.caller = caller;
RtThread.startMission();
}
protected int newHandle(int action, ResultType dataStruct) {
return newHandle(action, dataStruct, 0);
}
protected int newHandle(int action, ResultType dataStruct, int service) {
if (hid == 0) {
int ts;
ts = Timer.us();
for (int i = 0; i<2; i++) {
ts = ts * ts;
ts <<= 8;
ts >>>= 16;
}
hid = ts;
} else {
hid ++;
}
for (int i = 0; i < waitList.length; i++) {
if (waitList[i].xid == 0) {
waitList[i].xid = hid;
waitList[i].service = service;
waitList[i].action = action;
if (dataStruct != null) {
waitList[i].dataStruct = dataStruct;
}
break;
}
}
return hid;
}
/**
* used to look up the incoming xid in the list of outstanding messages
*
* @param xid the xid to search for
* @return the position of the xid in the list of outstanding messages on success, -1 otherwise
*/
protected int findXid(int xid) {
for (int i=0; i<MAX_PACKETS; i++) {
if (waitList[i].xid == xid) {
//System.out.println("diff: " + ((int)System.currentTimeMillis() - waitList[i].tstamp));
waitList[i].xid = 0;
return i;
}
}
return -1;
}
/**
* send the message
*
* @return the xid of the message sent
*/
protected int sendBuffer(StringBuffer rpcMessageBuffer, int destPort) {
int xid;
xid = Xdr.getIntAt(rpcMessageBuffer,0);
p = ejip.getFreePacket(ipLink);
if (p==null) {
//System.out.println("no free packet");
return 0;
} else {
net.getUdp().addHandler(10111, uClient);
Ip.setData(p, Udp.DATA, rpcMessageBuffer);
for (int i=0; i < (MAX_PACKETS - 1); i++) { //@WCA loop=8
if (waitList[i].xid == xid) {
// System.out.println("Put new packet "+xid+" in slot "+i);
waitList[i].tstamp = (int)System.currentTimeMillis();
i = MAX_PACKETS;
} else {
if (i == (MAX_PACKETS - 1)) {
//System.out.println("ERROR - no more free space in Rpc message buffer \"waitlist\"!");
}
}
}
net.getUdp().build(p, destIP, destPort);
}
return xid;
}
protected void handlePortmapStates(int port, int service) {
switch (service) {
case NfsConst.MOUNT_PROGRAM:
this.mount.setMountPort(port);
break;
case NfsConst.NFS_PROGRAM:
this.nfs.setNfsPort(port);
break;
/*
* case ACTION_QUERY_PORT_MAPPER_FOR_NLM:
* break;
*/
}
net.getUdp().addHandler(port+10000, uClient);
}
}