예제 #1
0
        /// <summary>
        /// Add a host to the list of known hosts to communicate with and raise the <see cref="SCHost.OnAdd"/> event.
        /// If there is already a host with the same IP address, then its nickname will be updated, no host will actually added and the <see cref="SCHost.OnAdd"/> event will not be raised.
        /// </summary>
        /// <param name="info">Information about the host to be added.</param>
        /// <param name="notifyConflict">If <code>true</code> detects nickname conflicts if any (raising the <see cref="SCHost.OnConflictNotification"/> and sending a conflict notification PDU to the other host).</param>
        /// <returns><code>true</code> if a host has actually been added, <code>false</code> if a nickname has been updated.</returns>
        public bool Add(SCHostInfo info, bool notifyConflict = true)
        {
            bool alreadyInserted = false;

            for (int i = 0; i < this.others.Count; i++)
            {
                if (this.others[i].Ip.Equals(info.Ip))
                {
                    alreadyInserted = true;
                    this.others[i]  = info;
                }
                else if (notifyConflict && this.others[i].Nickname == info.Nickname)
                {
                    SCPdu notification = new SCPdu(this.myself.ChatID, SCPduType.NicknameConflictNotification, Encoding.Default, Encoding.Default.GetBytes(info.Ip.ToString()));
                    this.ManualSend(this.others[i].Ip, notification);
                    notification.Payload = Encoding.Default.GetBytes(this.others[i].Ip.ToString());
                    this.ManualSend(info.Ip, notification);
                }
            }
            if (notifyConflict && info.Nickname == this.myself.Nickname)
            {
                SCPdu notification = new SCPdu(this.myself.ChatID, SCPduType.NicknameConflictNotification, Encoding.Default, Encoding.Default.GetBytes(IPAddress.Any.ToString()));
                this.ManualSend(info.Ip, notification);
                if (this.OnConflictNotification != null)
                {
                    this.OnConflictNotification(this.myself, info);
                }
            }
            if (!alreadyInserted)
            {
                this.others.Add(info);
            }
            return(!alreadyInserted);
        }
예제 #2
0
 /// <summary>
 /// Add a host to the list of known hosts to communicate with and raise the <see cref="SCHost.OnAdd"/> event.
 /// If there is already a host with the same IP address, then its nickname will be updated, no host will actually added and the <see cref="SCHost.OnAdd"/> event will not be raised.
 /// </summary>
 /// <param name="info">Information about the host to be added.</param>
 /// <param name="notifyConflict">If <code>true</code> detects nickname conflicts if any (raising the <see cref="SCHost.OnConflictNotification"/> and sending a conflict notification PDU to the other host).</param>
 /// <returns><code>true</code> if a host has actually been added, <code>false</code> if a nickname has been updated.</returns>
 public bool Add(SCHostInfo info, bool notifyConflict = true)
 {
     bool alreadyInserted = false;
     for (int i = 0; i < this.others.Count; i++)
     {
         if (this.others[i].Ip.Equals(info.Ip))
         {
             alreadyInserted = true;
             this.others[i] = info;
         }
         else if (notifyConflict && this.others[i].Nickname == info.Nickname)
         {
             SCPdu notification = new SCPdu(this.myself.ChatID, SCPduType.NicknameConflictNotification, Encoding.Default, Encoding.Default.GetBytes(info.Ip.ToString()));
             this.ManualSend(this.others[i].Ip, notification);
             notification.Payload = Encoding.Default.GetBytes(this.others[i].Ip.ToString());
             this.ManualSend(info.Ip, notification);
         }
     }
     if (notifyConflict && info.Nickname == this.myself.Nickname)
     {
         SCPdu notification = new SCPdu(this.myself.ChatID, SCPduType.NicknameConflictNotification, Encoding.Default, Encoding.Default.GetBytes(IPAddress.Any.ToString()));
         this.ManualSend(info.Ip, notification);
         if (this.OnConflictNotification != null)
         {
             this.OnConflictNotification(this.myself, info);
         }
     }
     if (!alreadyInserted)
     {
         this.others.Add(info);
     }
     return !alreadyInserted;
 }
예제 #3
0
        /// <summary>Initializes a new instance of the <see cref="SCHost"/> class.</summary>
        /// <param name="nickname">The nickname to be associated with this host.</param>
        /// <param name="chatID">The chat ID of the communication this host will take part into.</param>
        /// <param name="key">The encryption key used in this communication.</param>
        /// <param name="broadcast">The broadcast address of the local network.</param>
        /// <param name="port">The port to be used in this communication.</param>
        /// <param name="firstHello">If <code>true</code>, makes the host send a broadcast hello PDU once initialized.</param>
        public SCHost(string nickname, string chatID, byte[] key, IPAddress broadcast = null, int port = 4412, bool firstHello = true)
        {
            if (key.Length != 16)
            {
                throw new ScedaException("A SCEDA key must be 16 bytes long.");
            }
            this.myself = new SCHostInfo();
            this.myself.Nickname = nickname;
            this.myself.ChatID = chatID;
            this.myself.Port = port;
            this.key = key;
            this.others = new List<SCHostInfo>();
            this.socket = new UdpClient(this.myself.Port);
            this.socket.Client.EnableBroadcast = true;
            this.myself.Ip = IPAddress.Loopback;
            if (broadcast == null)
            {
                this.broadcast = IPAddress.Broadcast;
            }
            else
            {
                this.broadcast = broadcast;
            }
            this.disposed = false;
            this.remainingMalformedNotifications = 4;
            this.malformedTimer = new System.Timers.Timer(600000);
            this.malformedTimer.Elapsed += delegate
            {
                this.remainingMalformedNotifications = 4;
            };
            this.listener = new Thread(delegate()
            {
                for (; ; )
                {
                    IPEndPoint endPoint = new IPEndPoint(IPAddress.Any, this.myself.Port);
                    byte[] binaryPdu = this.socket.Receive(ref endPoint);
                    bool local = endPoint.Address.Equals(IPAddress.Loopback);
                    foreach (IPAddress item in Dns.GetHostAddresses(Dns.GetHostName()))
                    {
                        if (endPoint.Address.Equals(item))
                        {
                            local = true;
                        }
                    }
                    if (!local && SCPdu.CheckChatID(binaryPdu, this.myself.ChatID))
                    {
                        SCHostInfo info = new SCHostInfo(endPoint.Address, endPoint.Port, this.GetNicknameFromIp(endPoint.Address), this.myself.ChatID);
                        try
                        {
                            SCPdu pdu = SCPdu.FromBinary(binaryPdu, this.key);
                            switch (pdu.Type)
                            {
                                case SCPduType.Hello:
                                    {
                                        info.Nickname = pdu.Encoding.GetString(pdu.Payload);
                                        this.ManualSend(endPoint.Address, new SCPdu(this.myself.ChatID, SCPduType.Welcome, Encoding.Default, Encoding.Default.GetBytes(this.myself.Nickname)));
                                        if (this.Add(info, true) && this.OnHello != null)
                                        {
                                            this.OnHello(info);
                                        }
                                        break;
                                    }

                                case SCPduType.Welcome:
                                    {
                                        info.Nickname = pdu.Encoding.GetString(pdu.Payload);
                                        if (this.Add(info, true) && this.OnWelcome != null)
                                        {
                                            this.OnWelcome(info);
                                        }
                                        break;
                                    }

                                case SCPduType.Leave:
                                    {
                                        this.others.RemoveAll(item => item.Ip.Equals(info.Ip));
                                        if (this.OnLeave != null)
                                        {
                                            this.OnLeave(info);
                                        }
                                        break;
                                    }
                                case SCPduType.Message:
                                    {
                                        if (this.OnReceive != null)
                                        {
                                            this.OnReceive(info, pdu, pdu.Encoding.GetString(pdu.Payload));
                                        }
                                        break;
                                    }
                                case SCPduType.MalformedPduNotification:
                                    {
                                        if (this.OnMalformedNotification != null)
                                        {
                                            this.OnMalformedNotification(info, pdu.Payload);
                                        }
                                        break;
                                    }
                                case SCPduType.NicknameConflictNotification:
                                    {
                                        if (this.OnConflictNotification != null)
                                        {
                                            this.OnConflictNotification(info, new SCHostInfo(IPAddress.Parse(pdu.Encoding.GetString(pdu.Payload)), this.myself.Port, this.myself.Nickname, this.myself.ChatID));
                                        }
                                        break;
                                    }
                            }
                        }
                        catch (MalformedPduException)
                        {
                            this.remainingMalformedNotifications--;
                            if (this.remainingMalformedNotifications > -1)
                            {
                                this.ManualSend(endPoint.Address, new SCPdu(this.myself.ChatID, SCPduType.Hello, Encoding.Default, new byte[0]));
                                this.malformedTimer.Start();
                            }
                            if (this.OnMalformedReceived != null)
                            {
                                this.OnMalformedReceived(info, binaryPdu);
                            }
                        }
                    }
                }
            });
            this.listener.Start();
            if (firstHello)
            {
                this.Hello();
            }
        }
예제 #4
0
 static void myself_OnWelcome(SCHostInfo info)
 {
     int left;
     int top;
     ConsoleInsertLine(out left, out top);
     ConsoleWriteInColor(info.Nickname + " is online.", ConsoleColor.Blue);
     Console.SetCursorPosition(left, top);
 }
예제 #5
0
        /// <summary>Initializes a new instance of the <see cref="SCHost"/> class.</summary>
        /// <param name="nickname">The nickname to be associated with this host.</param>
        /// <param name="chatID">The chat ID of the communication this host will take part into.</param>
        /// <param name="key">The encryption key used in this communication.</param>
        /// <param name="broadcast">The broadcast address of the local network.</param>
        /// <param name="port">The port to be used in this communication.</param>
        /// <param name="firstHello">If <code>true</code>, makes the host send a broadcast hello PDU once initialized.</param>
        public SCHost(string nickname, string chatID, byte[] key, IPAddress broadcast = null, int port = 4412, bool firstHello = true)
        {
            if (key.Length != 16)
            {
                throw new ScedaException("A SCEDA key must be 16 bytes long.");
            }
            this.myself          = new SCHostInfo();
            this.myself.Nickname = nickname;
            this.myself.ChatID   = chatID;
            this.myself.Port     = port;
            this.key             = key;
            this.others          = new List <SCHostInfo>();
            this.socket          = new UdpClient(this.myself.Port);
            this.socket.Client.EnableBroadcast = true;
            this.myself.Ip = IPAddress.Loopback;
            if (broadcast == null)
            {
                this.broadcast = IPAddress.Broadcast;
            }
            else
            {
                this.broadcast = broadcast;
            }
            this.disposed = false;
            this.remainingMalformedNotifications = 4;
            this.malformedTimer          = new System.Timers.Timer(600000);
            this.malformedTimer.Elapsed += delegate
            {
                this.remainingMalformedNotifications = 4;
            };
            this.listener = new Thread(delegate()
            {
                for (; ;)
                {
                    IPEndPoint endPoint = new IPEndPoint(IPAddress.Any, this.myself.Port);
                    byte[] binaryPdu    = this.socket.Receive(ref endPoint);
                    bool local          = endPoint.Address.Equals(IPAddress.Loopback);
                    foreach (IPAddress item in Dns.GetHostAddresses(Dns.GetHostName()))
                    {
                        if (endPoint.Address.Equals(item))
                        {
                            local = true;
                        }
                    }
                    if (!local && SCPdu.CheckChatID(binaryPdu, this.myself.ChatID))
                    {
                        SCHostInfo info = new SCHostInfo(endPoint.Address, endPoint.Port, this.GetNicknameFromIp(endPoint.Address), this.myself.ChatID);
                        try
                        {
                            SCPdu pdu = SCPdu.FromBinary(binaryPdu, this.key);
                            switch (pdu.Type)
                            {
                            case SCPduType.Hello:
                                {
                                    info.Nickname = pdu.Encoding.GetString(pdu.Payload);
                                    this.ManualSend(endPoint.Address, new SCPdu(this.myself.ChatID, SCPduType.Welcome, Encoding.Default, Encoding.Default.GetBytes(this.myself.Nickname)));
                                    if (this.Add(info, true) && this.OnHello != null)
                                    {
                                        this.OnHello(info);
                                    }
                                    break;
                                }

                            case SCPduType.Welcome:
                                {
                                    info.Nickname = pdu.Encoding.GetString(pdu.Payload);
                                    if (this.Add(info, true) && this.OnWelcome != null)
                                    {
                                        this.OnWelcome(info);
                                    }
                                    break;
                                }

                            case SCPduType.Leave:
                                {
                                    this.others.RemoveAll(item => item.Ip.Equals(info.Ip));
                                    if (this.OnLeave != null)
                                    {
                                        this.OnLeave(info);
                                    }
                                    break;
                                }

                            case SCPduType.Message:
                                {
                                    if (this.OnReceive != null)
                                    {
                                        this.OnReceive(info, pdu, pdu.Encoding.GetString(pdu.Payload));
                                    }
                                    break;
                                }

                            case SCPduType.MalformedPduNotification:
                                {
                                    if (this.OnMalformedNotification != null)
                                    {
                                        this.OnMalformedNotification(info, pdu.Payload);
                                    }
                                    break;
                                }

                            case SCPduType.NicknameConflictNotification:
                                {
                                    if (this.OnConflictNotification != null)
                                    {
                                        this.OnConflictNotification(info, new SCHostInfo(IPAddress.Parse(pdu.Encoding.GetString(pdu.Payload)), this.myself.Port, this.myself.Nickname, this.myself.ChatID));
                                    }
                                    break;
                                }
                            }
                        }
                        catch (MalformedPduException)
                        {
                            this.remainingMalformedNotifications--;
                            if (this.remainingMalformedNotifications > -1)
                            {
                                this.ManualSend(endPoint.Address, new SCPdu(this.myself.ChatID, SCPduType.Hello, Encoding.Default, new byte[0]));
                                this.malformedTimer.Start();
                            }
                            if (this.OnMalformedReceived != null)
                            {
                                this.OnMalformedReceived(info, binaryPdu);
                            }
                        }
                    }
                }
            });
            this.listener.Start();
            if (firstHello)
            {
                this.Hello();
            }
        }
예제 #6
0
 static void myself_OnReceive(SCHostInfo info, SCPdu pdu, string message)
 {
     int left;
     int top;
     ConsoleInsertLine(out left, out top);
     if (info.Nickname == "")
     {
         ConsoleWriteInColor("unknown: ", ConsoleColor.Yellow);
     }
     else
     {
         ConsoleWriteInColor(info.Nickname + ": ", ConsoleColor.Cyan);
     }
     Console.Write(message);
     Console.SetCursorPosition(left, top);
 }
예제 #7
0
 private static void myself_OnMalformed(SCHostInfo info, byte[] pdu)
 {
     int left;
     int top;
     ConsoleInsertLine(out left, out top);
     ConsoleWriteInColor("Problem while communicating with " + info.Nickname, ConsoleColor.Red);
     if (info.Nickname == "")
     {
         ConsoleWriteInColor("unknown", ConsoleColor.Yellow);
     }
     ConsoleWriteInColor("!", ConsoleColor.Red);
     Console.SetCursorPosition(left, top);
 }
예제 #8
0
 static void myself_OnLeave(SCHostInfo info)
 {
     int left;
     int top;
     ConsoleInsertLine(out left, out top);
     ConsoleWriteInColor(info.Nickname + " is offline!", ConsoleColor.Green);
     Console.SetCursorPosition(left, top);
 }
예제 #9
0
 static void myself_OnHello(SCHostInfo info)
 {
     int left;
     int top;
     ConsoleInsertLine(out left, out top);
     ConsoleWriteInColor(info.Nickname + " has joined the chat!", ConsoleColor.Blue);
     Console.SetCursorPosition(left, top);
 }
예제 #10
0
 static void myself_OnConflictNotification(SCHostInfo informerInfo, SCHostInfo rivalInfo)
 {
     if (!conflictNotified)
     {
         conflictNotified = true;
         int left;
         int top;
         ConsoleInsertLine(out left, out top);
         ConsoleWriteInColor("Nickname conflict detected!", ConsoleColor.Red);
         Console.SetCursorPosition(left, top);
     }
 }