/base/Applications/TftpClient/tftp.cs
C# | 391 lines | 329 code | 33 blank | 29 comment | 61 complexity | e6e584b36544eaa0a70d286f0c7c8c45 MD5 | raw file
- ///////////////////////////////////////////////////////////////////////////////
- //
- // Microsoft Research Singularity
- //
- // Copyright (c) Microsoft Corporation. All rights reserved.
- //
- // Note:
- //
-
- using System;
- using System.Net.Sockets;
- using System.Net;
- using System.Text;
- using System.Threading;
-
- using Microsoft.Singularity;
- using Microsoft.Singularity.Directory;
- using Microsoft.Singularity.Channels;
- using Microsoft.Singularity.FileSystem;
- using Microsoft.Singularity.V1.Services;
-
- using FileSystem.Utils;
-
- namespace Microsoft.Singularity.Applications
- {
- internal enum TftpOpcode : ushort
- {
- RRQ=1, WRQ=2, DATA=3, ACK=4, ERROR=5
- };
-
- internal struct TftpHdr
- {
- public TftpOpcode Opcode;
- public ushort Arg;
-
- public TftpHdr(byte[]! buffer, int offset)
- {
- Opcode = (TftpOpcode)((ushort)buffer[offset+0] << 8 | buffer[offset+1]);
- Arg = (ushort)((ushort)buffer[offset+2] << 8 | buffer[offset+3]);
- // UnMarshal(buffer, offset);
- }
- public void Marshal(byte[]! buffer, int offset)
- {
- buffer[offset+0] = (byte)((ushort)Opcode>>8 & 0xff);
- buffer[offset+1] = (byte)((ushort)Opcode>>0 & 0xff);
- buffer[offset+2] = (byte)(Arg>>8 & 0xff);
- buffer[offset+3] = (byte)(Arg>>0 & 0xff);
- }
- public void UnMarshal(byte[]! buffer, int offset)
- {
- Opcode = (TftpOpcode)((ushort)buffer[offset+0] << 8 | buffer[offset+1]);
- Arg = (ushort)((ushort)buffer[offset+2] << 8 | buffer[offset+3]);
- }
- };
-
- public class TftpClient
- {
- Socket! s;
-
- public TftpClient(IPAddress! server)
- {
- Socket s = this.s = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
- IPEndPoint ep = new System.Net.IPEndPoint(server, 69);
- Console.Write("EP= {0}\n", ep);
- // Connect here
- s.Connect(ep);
- }
-
- static int BuildRequest(byte[]! packet, TftpOpcode op, string! filename)
- {
- TftpHdr hdr = new TftpHdr();
- byte[] tmp;
-
- hdr.Opcode = op;
- hdr.Marshal(packet, 0);
- int off = 2;
- tmp = Encoding.ASCII.GetBytes(filename);
- tmp.CopyTo(packet, off);
- off += tmp.Length;
- packet[off++] = 0;
- tmp = Encoding.ASCII.GetBytes("octet");
- tmp.CopyTo(packet, off);
- off += tmp.Length;
- packet[off++] = 0;
- Console.WriteLine("Done");
- return off;
- }
-
- public string Get(string! filename, string localName, bool verboseMode)
- {
- TftpHdr hdr = new TftpHdr();
- byte[] request;
- byte[] reply = new byte[8192];
- int success;
- FileContract.Imp persistHandle = null ;
- long curPos = 0 ;
- int len;
- int rc;
-
- if (null != localName) {
- Console.WriteLine ("Creating file "+localName);
- success = FileUtils.CreateFile(localName);
- if (0 == success) {
- persistHandle = FileUtils.OpenFile(localName);
- if (null == persistHandle) {
- Console.WriteLine("unable to open file " + localName);
- return "";
- }
- }
- else {
- Console.WriteLine("unable to create file " + localName);
- return "";
- }
- }
-
- request = new byte[4 + 512];
-
- len = BuildRequest(request, TftpOpcode.RRQ, filename);
- bool done = false;
- hdr.UnMarshal(request, 0);
- rc = s.Send(request, len, SocketFlags.None);
- if (verboseMode) Console.WriteLine("Sent RRQ rc={0}", rc);
-
- byte []! in ExHeap buf = new[ExHeap] byte[512];
- //string str = null;
- int count = 0;
- int lastBlock = -1;
- while (!done) {
- //Socket.Select(listenList, null, null, 1000);
- if (s.Poll(1000000, SelectMode.SelectRead)) {
- rc = s.Receive(reply);
- if (verboseMode) Console.WriteLine("Receive rc={0}", rc);
- if (rc >= 4) {
- TftpHdr rh = new TftpHdr(reply, 0);
- //Console.WriteLine("Opcode {0} Arg {1} rc={2} curPos={3}", rh.Opcode, rh.Arg, rc, curPos);
- if (rh.Arg == lastBlock)
- Console.WriteLine(" duplicate block? block ="+rh.Arg);
- lastBlock = rh.Arg;
- if (rh.Opcode == TftpOpcode.DATA) {
- if (!verboseMode) {
- Console.Write(".");
- if (count++ > 50) {
- count = 0;
- Console.Write("\n");
- }
- }
- else {
- //str = Encoding.ASCII.GetString(reply, 4, rc-4);
- //Console.WriteLine("pos="+curPos+" str="+str);
- //str = null;
- }
- if (persistHandle != null) {
- Bitter.FromByteArray(buf,0,rc-4,reply,4);
- persistHandle.SendWrite(buf,0,curPos,rc-4);
- switch receive {
- case persistHandle.AckWrite( _buf, bytesWritten, error) :
- buf = _buf;
- curPos = rh.Arg * 512;
- break;
- case persistHandle.ChannelClosed() :
- Console.WriteLine("File handle closed. Quitting");
- delete persistHandle;
- return null;
- break;
- case unsatisfiable:
- Console.WriteLine("receive is unsatisfiable. Quitting");
- delete persistHandle;
- return null;
- break;
- }
- }
- }
- // Build new ack packet - acts as REQ for next block
- hdr.Opcode = TftpOpcode.ACK;
- hdr.Arg = rh.Arg;
- hdr.Marshal(request, 0);
- len = 4;
- }
- if (rc < 512 + 4) done = true;
- }
- else {
- //Console.WriteLine("poll for data failed!");
- //return null;
- }
- rc = s.Send(request, len, SocketFlags.None);
- if (verboseMode)Console.WriteLine("Sent {0} {1} rc {2}", hdr.Opcode, hdr.Arg, rc);
- //Thread.Sleep(1000);
- }
- if (persistHandle != null) {
- Console.WriteLine("Closing EP handle via delete");
- delete persistHandle;
- }
- delete buf;
- return null;
- }
-
- public string Put(string! filename, string localName)
- {
- TftpHdr hdr = new TftpHdr();
- byte[] request;
- byte[] reply = new byte[8192];
- byte []! in ExHeap buf;
- FileContract.Imp fileHandle = null ;
-
- int len;
- int rc;
- long fileLength = 0;
- ErrorCode errorOut;
-
- if (null != localName) {
- DirectoryServiceContract.Imp! rootNS = DirectoryService.NewClientEndpoint();
- FileAttributesRecord record;
- bool ok = FileUtils.GetAttributes(localName, rootNS, out record, out errorOut);
- delete rootNS;
-
- if (!ok) {
- Console.WriteLine("Unable to open file ({0}) for send. reason:{1}",
- localName, SdsUtils.ErrorCodeToString(errorOut)
- );
- return null;
- }
-
- fileLength = record.FileSize;
-
- fileHandle = FileUtils.OpenFile(localName);
- if (null == fileHandle) {
- Console.WriteLine("Unable to open file "+localName+" for send");
- return null;
- }
- }
- request = new byte[4 + 512];
-
- len = BuildRequest(request, TftpOpcode.WRQ, filename);
- int pos = 0;
- bool done = false;
-
- rc = s.Send(request, len, SocketFlags.None);
- Console.WriteLine("Sent WRQ rc={0}", rc);
-
- buf = new[ExHeap] byte[512];
- int threshold = 20;
- int waitCount = 0;
- Console.WriteLine(" file size =" + fileLength);
- while (!done) {
- //Socket.Select(listenList, null, null, 1000);
- if (s.Poll(100000, SelectMode.SelectRead)) {
- rc = s.Receive(reply);
- Console.WriteLine("Receive rc={0}", rc);
- if (rc >= 4) {
- TftpHdr rh = new TftpHdr(reply, 0);
- Console.WriteLine("PUT: Opcode {0} Arg {1}", rh.Opcode, rh.Arg);
-
- if (rh.Opcode == TftpOpcode.ACK) {
- int datalen;
- int error;
- long bytesRead;
- Console.WriteLine("ACK for block {0}, pos={1}", rh.Arg,pos);
- waitCount = 0;
- if (pos >= fileLength) {
- Console.WriteLine(" here");
- bytesRead = 0;
- }
- else {
- if (fileHandle == null)
- throw new Exception("fileHandle is null when I want to SendRead");
- fileHandle.SendRead(buf, 0, pos, 512);
- fileHandle.RecvAckRead(out buf, out bytesRead, out error);
- if (error != 0) DebugStub.Break();
-
- // If we get an ack we can send the next block
- pos = (rh.Arg+1) * 512;
- }
- // Build new DATA packet
- hdr.Opcode = TftpOpcode.DATA;
- hdr.Arg = rh.Arg;
- hdr.Arg++;
- hdr.Marshal(request, 0);
- datalen = Math.Min(512, (int)bytesRead);
- if (datalen < 512) done = true;
- //Encoding.ASCII.GetBytes(contents, pos, datalen, request, 4);
- Bitter.ToByteArray(buf,0,datalen,request,4);
- len = 4 + datalen;
- }
- else {
- Console.WriteLine("NOT AN ACK!\n");
- DebugStub.Break();
- }
- }
- rc = s.Send(request, len, SocketFlags.None);
- Console.WriteLine("Sent {0} {1} rc {2}", hdr.Opcode, hdr.Arg, rc);
- }
- else {
- Console.WriteLine("Waiting.");
- waitCount++;
- if (waitCount > threshold) {
- Console.WriteLine (" exceeded timeout threshold");
- done = true;
- break;
- }
- }
- //Thread.Sleep(1000);
- }
- Console.WriteLine("Done");
- delete buf;
- if (fileHandle != null)
- delete fileHandle;
- return null;
- }
-
- private static IPAddress GetServerAddress(string server)
- {
- try {
- return IPAddress.Parse(server);
- }
- catch {
- }
-
- try {
- IPHostEntry he = Dns.GetHostByName(server);
- return he.AddressList[0];
- }
- catch {
- }
- return null;
- }
-
- private static void Usage()
- {
- Console.WriteLine("Usage: tftpclient <server> [-i] <put|get> <getfilename> [ <putfilename> ]");
- }
-
- /// <summary>
- /// The main entry point for the application.
- /// </summary>
- public static int Main(string[]! args)
- {
- bool verboseMode = false;
- String localName, remoteName;
- if (args.Length < 4 || args.Length > 6) {
- Usage();
- return 1;
- }
-
- IPAddress server = GetServerAddress(args[1]);
- if (server == null) {
- Console.WriteLine("Could not find server : {0}", args[1]);
- return 2;
- }
-
- int pos =2;
- if (args[pos] == "-v") {
- verboseMode = true;
- pos++;
- }
-
- bool doGet;
- switch (args[pos]) {
- case "get":
- doGet = true;
- break;
- case "put":
- doGet = false;
- break;
- default:
- Usage();
- return -1;
- }
- pos++;
- remoteName = (!)args[pos];
- pos++;
- localName = null;
- if (pos >= args.Length) {
- Console.WriteLine("no destination given");
- }
- else {
- localName = args[pos];
- }
- Console.WriteLine("doGet="+doGet+" src="+remoteName+" dest="+localName);
- TftpClient tftpClient = new TftpClient(server);
- if (doGet) {
- string contents = tftpClient.Get(remoteName,localName,verboseMode);
- if (verboseMode) Console.WriteLine("Contents:\n{0}", contents);
- }
- else {
- //put
- tftpClient.Put(remoteName,localName);
- }
- return 0;
- } // end Main
- } // end class TftpClient
- } // end namespace Microsoft.Singularity.Shell