Ejemplo n.º 1
0
        public static bool[] GetBitArray(int x)
        {
            BitArray b = new BitArray(new int[] { x });
            var bools = b.Cast<bool>();
            //the visual representation is the opposite of how they bits actually go in the array so reverse things
            return bools.Reverse().ToArray();

               // bool[] bits = b.Cast<bool>().Select(bit => bit ? 1 : 0).ToArray();
        }
Ejemplo n.º 2
0
        internal static byte ConvertToByte(BitArray bits)
        {
            if (bits.Count != 8)
            {
                throw new ArgumentException("bits");
            }

            byte[] bytes = new byte[1];
            var reversed = new BitArray(bits.Cast<bool>().Reverse().ToArray());
            reversed.CopyTo(bytes, 0);
            return bytes[0];
        }
Ejemplo n.º 3
0
 private static void PopulatePrimes(int upTo)
 {
     if(upTo <= s_Primes.DefaultIfEmpty().Max())
         return;
     var bitArray = new BitArray(upTo*100);
     bitArray[0] = false;
     bitArray[1] = false;
     for (var i = 2; i < bitArray.Length; i++)
         if (bitArray[i])
             for (var j = i * 2; j < bitArray.Length; j += i)
                 bitArray[j] = false;
     s_Primes = bitArray.Cast<bool>().Select((x, y) => new { x, y }).Where(x => x.x).Select(x => x.y).ToList();
 }
Ejemplo n.º 4
0
        public void GetLogicalDrives_Windows_MatchesExpectedLetters()
        {
            string[] drives = Environment.GetLogicalDrives();

            uint mask = (uint)GetLogicalDrives();
            var bits = new BitArray(new[] { (int)mask });

            Assert.Equal(bits.Cast<bool>().Count(b => b), drives.Length);
            for (int bit = 0, d = 0; bit < bits.Length; bit++)
            {
                if (bits[bit])
                {
                    Assert.Contains((char)('A' + bit), drives[d++]);
                }
            }
        }
Ejemplo n.º 5
0
            public void Run(object threadContext)
            {
                object[] thrContextObjects = (object[])threadContext;
                Context ctx = (Context)thrContextObjects[0];

                using (Socket ctl = ctx.Socket(SocketType.REP))
                {
                    // Bind the control reply socket:
                    ctl.SndBuf = 1048576 * 20;
                    if (host.tsp == Transport.TCP)
                    {
                        ctl.Bind(Transport.TCP, host.device, (host.port + 1));
                    }
                    else
                    {
                        ctl.Bind(Transport.TCP, "*", (host.port + 1));
                    }

                    // Wait for the sockets to bind:
                    Thread.Sleep(500);

                    // Create a poller on the control socket to handle client requests:
                    PollItem[] pollItems = new PollItem[1];
                    pollItems[0] = ctl.CreatePollItem(IOMultiPlex.POLLIN);
                    pollItems[0].PollInHandler += new PollHandler((Socket sock, IOMultiPlex mp) =>
                    {
                        Queue<byte[]> request = sock.RecvAll();

                        // Bad message?
                        if (request.Count == 0) return;

                        Guid clientIdentity = new Guid(request.Dequeue().Skip(1).ToArray());
                        ClientState client;
                        bool newClient = false;

                        lock (host.clientLock)
                        {
                            if (!host.clients.ContainsKey(clientIdentity))
                            {
                                client = new ClientState(clientIdentity);
                                host.clients.Add(clientIdentity, client);
                                newClient = true;
                            }
                            else
                            {
                                client = host.clients[clientIdentity];
                            }

                            // Update last message received time to now:
                            client.LastMessageTime = DateTimeOffset.UtcNow;
                        }

                        string cmd = Encoding.Unicode.GetString(request.Dequeue());

                        // Process the client command:
                        trace("{0}: Client sent '{1}'", clientIdentity.ToString(), cmd);
                        switch (cmd)
                        {
                            case "JOIN":
                                sock.SendMore("JOINED", Encoding.Unicode);

                                ReadOnlyCollection<FileInfo> files = host.tarball.Files;

                                sock.SendMore(BitConverter.GetBytes(host.numChunks));
                                sock.SendMore(BitConverter.GetBytes(host.chunkSize));
                                sock.SendMore(BitConverter.GetBytes(host.tarball.Files.Count));

                                foreach (var fi in files)
                                {
                                    string fiName = fi.FullName.Substring(host.basePath.Length);
                                    sock.SendMore(fiName, Encoding.Unicode);
                                    sock.SendMore(BitConverter.GetBytes(fi.Length));
                                    sock.SendMore(new byte[16]);
                                }

                                sock.Send("", Encoding.Unicode);
                                trace("{0}: Sent JOINED response", clientIdentity.ToString());
                                if (host.ClientJoined != null) host.ClientJoined(host, clientIdentity);
                                break;

                            case "NAKS":
                                // Receive the client's current NAK:
                                byte[] tmp = request.Dequeue();
                                if (tmp.Length != host.numBitArrayBytes)
                                {
                                    trace("{0}: Bad NAKs", clientIdentity.ToString());
                                    sock.Send("BADNAKS", Encoding.Unicode);
                                    break;
                                }
                                sock.Send("", Encoding.Unicode);

                                lock (host.clientLock)
                                {
                                    BitArray newNAKs = new BitArray(tmp);
                                    // Add to the running ACK count the number of chunks turned from NAK to ACK in this update:
                                    if (client.HasNAKs)
                                    {
                                        client.RunningACKCount += (
                                            from i in Enumerable.Range(0, host.numChunks)
                                            where (client.NAK[i] == true) && (newNAKs[i] == false)
                                            select i
                                        ).Count();
                                    }
                                    else
                                    {
                                        client.RunningACKCount += newNAKs.Cast<bool>().Take(host.numChunks).Count(b => !b);
                                    }
                                    // Update to the new NAK state:
                                    client.NAK = newNAKs;

                                    // Inform the server to update the program:
                                    host.haveNewNAKs = true;
                                }

                                trace("{0}: NAKs received", clientIdentity.ToString());
                                if (host.ChunksACKed != null) host.ChunksACKed(host);
                                break;

                            case "LEAVE":
                                sock.Send("LEFT", Encoding.Unicode);

                                lock (host.clientLock)
                                {
                                    // Remove the client's state record:
                                    host.clients.Remove(clientIdentity);
                                }

                                if (host.ClientLeft != null) host.ClientLeft(host, clientIdentity, ClientLeaveReason.Left);

                                trace("{0}: Client left", clientIdentity.ToString());
                                break;

                            case "ALIVE":
                                if (newClient)
                                {
                                    trace("{0}: WHOAREYOU", clientIdentity.ToString());
                                    byte[] sendIdentity = new byte[1] { (byte)'@' }.Concat(clientIdentity.ToByteArray()).ToArray();
                                    sock.Send("WHOAREYOU", Encoding.Unicode);
                                    break;
                                }

                                // Fantastic.
                                sock.Send("", Encoding.Unicode);
                                break;

                            default:
                                // Unknown command.
                                sock.Send("UNKNOWN", Encoding.Unicode);
                                trace("{0}: Unknown request", clientIdentity.ToString());
                                break;
                        }

                        request = null;
                    });

                    while (host.isRunning)
                    {
                        while (ctx.Poll(pollItems, 100000L) == 1)
                        {
                        }
                    }
                }
            }
Ejemplo n.º 6
0
        /// <summary>
        /// Main thread to host the client process.
        /// </summary>
        /// <param name="threadContext">A ZMQ.Context instance.</param>
        public void Run(object threadContext)
        {
            try
            {
                Context ctx = (Context)threadContext;

                // This would be a using statement on data and ctl but we need to close and reopen sockets, which means
                // we have to Dispose() of a socket early and create a new instance. C#, wisely so, prevents you from
                // reassigning a using variable.
                Socket data = null, ctl = null, disk = null, diskACK = null;
                try
                {
                    data = ctx.Socket(SocketType.SUB);
                    ctl = ctx.Socket(SocketType.REQ);
                    disk = new Socket(SocketType.PUSH);
                    diskACK = new Socket(SocketType.PULL);

                    // Set the HWM for the disk PUSH so that the PUSH blocks if the PULL can't keep up writing:
                    if (diskHWM > 0) disk.SNDHWM = diskHWM;
                    //disk.SndBuf = 1048576 * diskHWM * 4;

                    // inproc:// binds are immediate.
                    disk.Bind("inproc://disk");
                    diskACK.Bind("inproc://diskack");

                    // Create the disk PULL thread:
                    Thread diskWriterThread = new Thread(new ParameterizedThreadStart(DiskWriterThread));
                    diskWriterThread.Start(ctx);

                    data.RCVHWM = networkHWM;

                    //data.RcvBuf = 1048576 * hwm * 4;
                    // NOTE: work-around for MS bug in WinXP's networking stack. See http://support.microsoft.com/kb/201213 for details.
                    data.RcvBuf = 0;

                    if (tsp == Transport.EPGM || tsp == Transport.PGM)
                    {
                        data.Rate = pgmRate;
                    }

                    string address = tsp.ToString().ToLower() + "://" + deviceData + ":" + portData;
                    Console.WriteLine("Connect(\"{0}\")", address);
                    data.Connect(address);
                    data.Subscribe(subscription, Encoding.Unicode);

                    // Connect to the control request socket:
                    ctl.RcvBuf = 1048576 * 4;
                    ctl.SndBuf = 1048576 * 4;
                    address = "tcp://" + deviceCtl + ":" + portCtl.ToString();
                    Console.WriteLine("Connect(\"{0}\")", address);
                    ctl.Connect(address);

                    Guid myIdentity = Guid.NewGuid();
                    ctl.Identity = new byte[1] { (byte)'@' }.Concat(myIdentity.ToByteArray()).ToArray();

                    Thread.Sleep(500);

                    // Begin client logic:

                    naks = null;
                    numBytes = 0;
                    int ackCount = -1;
                    byte[] nakBuf = null;

                    bool shuttingDown = false;

                    Stopwatch recvTimer = Stopwatch.StartNew();
                    long lastElapsedMilliseconds = recvTimer.ElapsedMilliseconds;
                    int msgsRecv = 0, msgsWritten = 0;

                    try
                    {
                        // Poll for incoming messages on the data SUB socket:
                        PollItem[] pollItems = new PollItem[3];
                        pollItems[0] = data.CreatePollItem(IOMultiPlex.POLLIN);
                        pollItems[1] = ctl.CreatePollItem(IOMultiPlex.POLLIN /* | IOMultiPlex.POLLOUT */);
                        pollItems[2] = diskACK.CreatePollItem(IOMultiPlex.POLLIN);

                        ZMQStateMasheen<DataSUBState> dataFSM;
                        ZMQStateMasheen<ControlREQState> controlFSM;
                        Queue<QueuedControlMessage> controlStateQueue = new Queue<QueuedControlMessage>();

                        DateTimeOffset lastSentNAKs = DateTimeOffset.UtcNow.Subtract(TimeSpan.FromSeconds(60));

                        // We create a state machine to handle our send/recv state:
                        dataFSM = new ZMQStateMasheen<DataSUBState>(
                            // Set the initial state:
                            DataSUBState.Recv,
                            // Initial state handler:
                            new ZMQStateMasheen<DataSUBState>.State(DataSUBState.Recv, (sock, revents) =>
                            {
                                Queue<byte[]> packet = sock.RecvAll();

                                if (packet.Count == 0) { trace("FAIL!"); return DataSUBState.Recv; }
                                string sub = Encoding.Unicode.GetString(packet.Dequeue());
                                if (packet.Count == 0) { trace("FAIL!"); return DataSUBState.Recv; }
                                string cmd = Encoding.Unicode.GetString(packet.Dequeue());

                                if ((naks != null) && (cmd == "DATA"))
                                {
                                    if (packet.Count == 0) { trace("FAIL!"); return DataSUBState.Recv; }
                                    int chunkIdx = BitConverter.ToInt32(packet.Dequeue(), 0);

                                    // Count the number of messages received from the network:
                                    ++msgsRecv;
                                    if (ChunkReceived != null) ChunkReceived(this, chunkIdx);

                                    // Already received this chunk?
                                    if (!naks[chunkIdx])
                                    {
                                        trace("ALREADY RECV {0}", chunkIdx);
                                        return DataSUBState.Recv;
                                    }

                                    trace("RECV {0}", chunkIdx);

                                    // Queue up the disk writes with PUSH/PULL and an HWM on a separate thread to maintain as
                                    // constant disk write throughput as we can get... The HWM will enforce the PUSHer to block
                                    // when the PULLer cannot receive yet.
                                    if (packet.Count == 0) return DataSUBState.Recv;
                                    byte[] chunk = packet.Dequeue();
                                    disk.SendMore(cmdWrite);
                                    disk.SendMore(BitConverter.GetBytes(chunkIdx));
                                    // This will block if the disk queue gets full:
                                    disk.Send(chunk);
                                    chunk = null;

                                    return DataSUBState.Recv;
                                }
                                else if (cmd == "PING")
                                {
                                    if (shuttingDown) return DataSUBState.Recv;

                                    controlStateQueue.Enqueue(new QueuedControlMessage(ControlREQState.SendALIVE, null));
                                    return DataSUBState.Recv;
                                }
                                else
                                {
                                    return DataSUBState.Recv;
                                }
                            })
                        );

                        // We create a state machine to handle our send/recv state:
                        object tmpControlState = null;
                        controlFSM = new ZMQStateMasheen<ControlREQState>(
                            ControlREQState.Nothing,
                            new ZMQStateMasheen<ControlREQState>.State(ControlREQState.Nothing, (sock, revents) =>
                            {
                                // Do nothing state.
                                return ControlREQState.Nothing;
                            }),
                            new ZMQStateMasheen<ControlREQState>.State(ControlREQState.SendALIVE, (sock, revents) =>
                            {
                                if (shuttingDown) return ControlREQState.Nothing;

                                ctl.SendMore(ctl.Identity);
                                ctl.Send("ALIVE", Encoding.Unicode);

                                return new ZMQStateMasheen<ControlREQState>.MoveOperation(ControlREQState.RecvALIVE, false);
                            }),
                            new ZMQStateMasheen<ControlREQState>.State(ControlREQState.RecvALIVE, (sock, revents) =>
                            {
                                Queue<byte[]> packet = ctl.RecvAll();

                                if (packet.Count == 0) return ControlREQState.Nothing;
                                string cmd = Encoding.Unicode.GetString(packet.Dequeue());
                                //trace("Server: '{0}'", cmd);

                                if (cmd == "") return ControlREQState.Nothing;
                                else if (cmd == "WHOAREYOU") return new ZMQStateMasheen<ControlREQState>.MoveOperation(ControlREQState.SendJOIN, true);

                                return ControlREQState.Nothing;
                            }),
                            new ZMQStateMasheen<ControlREQState>.State(ControlREQState.SendJOIN, (sock, revents) =>
                            {
                                if (shuttingDown) return ControlREQState.Nothing;

                                // Send a JOIN request:
                                ctl.SendMore(ctl.Identity);
                                ctl.Send("JOIN", Encoding.Unicode);

                                return ControlREQState.RecvJOIN;
                            }),
                            new ZMQStateMasheen<ControlREQState>.State(ControlREQState.RecvJOIN, (sock, revents) =>
                            {
                                Queue<byte[]> packet = ctl.RecvAll();
                                if (packet.Count == 0) return ControlREQState.Nothing;

                                string resp = Encoding.Unicode.GetString(packet.Dequeue());
                                if (resp != "JOINED")
                                {
                                    // TODO: handle this failure.
                                    trace("FAIL!"); return ControlREQState.Nothing;
                                }

                                // TODO: make this atomically succeed or fail without corrupting state
                                if (packet.Count == 0) { trace("FAIL!"); return ControlREQState.Nothing; }
                                numChunks = BitConverter.ToInt32(packet.Dequeue(), 0);
                                numBytes = ((numChunks + 7) & ~7) >> 3;
                                nakBuf = new byte[numBytes];
                                if (packet.Count == 0) { trace("FAIL!"); return ControlREQState.Nothing; }
                                chunkSize = BitConverter.ToInt32(packet.Dequeue(), 0);
                                if (packet.Count == 0) { trace("FAIL!"); return ControlREQState.Nothing; }
                                int numFiles = BitConverter.ToInt32(packet.Dequeue(), 0);

                                List<TarballEntry> tbes = new List<TarballEntry>(numFiles);
                                for (int i = 0; i < numFiles; ++i)
                                {
                                    if (packet.Count == 0) { trace("FAIL!"); return ControlREQState.Nothing; }
                                    string fiName = Encoding.Unicode.GetString(packet.Dequeue());
                                    if (packet.Count == 0) { trace("FAIL!"); return ControlREQState.Nothing; }
                                    long length = BitConverter.ToInt64(packet.Dequeue(), 0);
                                    if (packet.Count == 0) { trace("FAIL!"); return ControlREQState.Nothing; }
                                    byte[] hash = packet.Dequeue();

                                    TarballEntry tbe = new TarballEntry(fiName, length, hash);
                                    tbes.Add(tbe);
                                }

                                lock (tarballLock)
                                {
                                    if (tarball != null)
                                    {
                                        tarball.Close();
                                        tarball.Dispose();
                                        tarball = null;
                                    }
                                }

                                lock (tarballLock)
                                {
                                    // Create the tarball reader that writes the files locally:
                                    tarball = new TarballStreamReader(downloadDirectory, tbes);

                                    // Get our local download state:
                                    naks = getClientState(this, tarball);
                                }
                                ackCount = naks.Cast<bool>().Take(numChunks).Count(b => !b);

                                return new ZMQStateMasheen<ControlREQState>.MoveOperation(ControlREQState.SendNAKS, true);
                            }),
                            new ZMQStateMasheen<ControlREQState>.State(ControlREQState.SendNAKS, (sock, revents) =>
                            {
                                if (shuttingDown) return ControlREQState.Nothing;

                                if (nakBuf == null) return ControlREQState.Nothing;

                                // Send our NAKs:
                                ctl.SendMore(ctl.Identity);
                                ctl.SendMore("NAKS", Encoding.Unicode);
                                // TODO: RLE!
                                naks.CopyTo(nakBuf, 0);
                                trace("SEND NAK");
                                ctl.Send(nakBuf);

                                return ControlREQState.RecvNAKS;
                            }),
                            new ZMQStateMasheen<ControlREQState>.State(ControlREQState.RecvNAKS, (sock, revents) =>
                            {
                                Queue<byte[]> packet = ctl.RecvAll();
                                // Don't care what the response is for now.

                                return ControlREQState.Nothing;
                            })
                        );

                        // Disk-write acknowledgement poll input handler:
                        pollItems[2].PollInHandler += new PollHandler((Socket sock, IOMultiPlex revents) =>
                        {
                            byte[] idxPkt = sock.RecvAll().Dequeue();

                            int chunkIdx = BitConverter.ToInt32(idxPkt, 0);
                            naks[chunkIdx] = false;

                            // Count the number of messages written to disk:
                            ++msgsWritten;
                            ++ackCount;

                            // Profiled - terrible performance. Not a big surprise here.
                            //ackCount = naks.Cast<bool>().Take(numChunks).Count(b => !b);

                            // If we ran up the timer, send more ACKs:
                            if (DateTimeOffset.UtcNow.Subtract(lastSentNAKs).TotalMilliseconds >= 250d)
                            {
                                lastSentNAKs = DateTimeOffset.UtcNow;
                                controlStateQueue.Enqueue(new QueuedControlMessage(ControlREQState.SendNAKS, null));
                            }
                        });

                        pollItems[0].PollInHandler += new PollHandler(dataFSM.StateMasheen);
                        pollItems[1].PollInHandler += new PollHandler(controlFSM.StateMasheen);

                        DateTimeOffset lastRecv = DateTimeOffset.UtcNow;

                        // Start the control state machine with a JOIN:
                        controlStateQueue.Enqueue(new QueuedControlMessage(ControlREQState.SendJOIN, null));

                        // Create a socket poller for the data socket:
                        while (true)
                        {
                            // If we disposed of the previous control socket, create a new one:
                            if (ctl == null)
                            {
                                trace("Creating new CONTROL socket");
                                // Set up new socket:
                                ctl = ctx.Socket(SocketType.REQ);
                                // Connect to the control request socket:
                                ctl.Connect("tcp://" + deviceCtl + ":" + portCtl.ToString());
                                ctl.Identity = new byte[1] { (byte)'@' }.Concat(myIdentity.ToByteArray()).ToArray();
                            }

                            if (!shuttingDown && IsSendState(controlFSM.CurrentState))
                            {
                                // If we ran up the timer, send more NAKs:
                                if (DateTimeOffset.UtcNow.Subtract(lastSentNAKs).TotalMilliseconds >= 200d)
                                {
                                    lastSentNAKs = DateTimeOffset.UtcNow;
                                    controlStateQueue.Enqueue(new QueuedControlMessage(ControlREQState.SendNAKS, null));
                                }

                                if (controlStateQueue.Count > 0)
                                {
                                    var msg = controlStateQueue.Dequeue();

                                    // Roll up similar state requests:
                                    int dupes = 0;
                                    while (controlStateQueue.Count > 0)
                                    {
                                        if (controlStateQueue.Peek().NewState != msg.NewState) break;

                                        msg = controlStateQueue.Dequeue();
                                        ++dupes;
                                    }

                                    if (dupes > 0)
                                    {
                                        trace("Removed {0} redundant queued states", dupes);
                                    }

                                    tmpControlState = msg.Object;

                                    // Run the control state machine to SEND:
                                    controlFSM.CurrentState = msg.NewState;
                                    controlFSM.StateMasheen(ctl, IOMultiPlex.POLLOUT);
                                }
                            }

                            // Measure our message send rate per minute:
                            long elapsed = recvTimer.ElapsedMilliseconds - lastElapsedMilliseconds;
                            if (elapsed >= 100L)
                            {
                                NetworkRecvChunksPerMinute = (int)((msgsRecv * 60000L) / elapsed);
                                DiskWriteChunksPerMinute = (int)((msgsWritten * 60000L) / elapsed);
                                lastElapsedMilliseconds = recvTimer.ElapsedMilliseconds;
                                msgsRecv = 0;
                                msgsWritten = 0;
                            }

                            if (!recvTimer.IsRunning)
                            {
                                recvTimer.Reset();
                                recvTimer.Start();
                                lastElapsedMilliseconds = 0L;
                            }

                            if (ackCount >= numChunks)
                            {
                                disk.Send(cmdExit);
                                break;
                            }

                            if (ctx.Poll(pollItems, 100L) == 0)
                                Thread.Sleep(1);
                        }

                        // Wait for the disk writer to finish up:
                        shuttingDown = true;
                        diskWriterThread.Join();

                        // If we were last to await some response, receive it:
                        if (controlFSM.CurrentState == ControlREQState.RecvALIVE || controlFSM.CurrentState == ControlREQState.RecvJOIN || controlFSM.CurrentState == ControlREQState.RecvNAKS)
                        {
                            PollItem[] recvPoll = new PollItem[1];
                            recvPoll[0] = ctl.CreatePollItem(IOMultiPlex.POLLIN);
                            recvPoll[0].PollInHandler += new PollHandler(controlFSM.StateMasheen);

                            // Wait a bit to receive the response:
                            for (int i = 0; (i < 20) && ((ctx.Poll(recvPoll, 100) == 1) && (ctl != null)); ++i)
                            {
                            }
                        }

                        // Send the LEAVE message:
                        ctl.SendMore(ctl.Identity);
                        ctl.Send("LEAVE", Encoding.Unicode);
                        Completed = true;
                    }
                    finally
                    {
                        if (tarball != null) tarball.Dispose();
                    }
                }
                finally
                {
                    if (data != null) data.Dispose();
                    if (ctl != null) ctl.Dispose();
                }
            }
            catch (System.Exception ex)
            {
                Console.Error.WriteLine(ex.ToString());
            }
        }
Ejemplo n.º 7
0
 public void Write(byte value)
 {
     var bits = new BitArray(new byte[] { value });
     foreach(var b in bits.Cast<bool>())
     {
         Write(b);
     }
 }
Ejemplo n.º 8
0
 public static IEnumerable <bool> AsEnumerable(this System.Collections.BitArray source)
 {
     TypeCheckEnumerable(source, s => s.AsEnumerable(), (s) => s[0]);
     return(source.Cast <bool>());
 }