예제 #1
0
        public static bool TryParse(BDictionary message, out FindNodeQuery query)
        {
            if (message.Contains("q", new BString("find_node")) &&
                message.TryGetValue("t", out BString transactionId) && transactionId.Length > 0 &&
                message.TryGetValue("a", out BDictionary arguments) &&
                arguments.TryGetValue("id", out BString nodeId) && nodeId.Length == NodeID.Size &&
                arguments.TryGetValue("target", out BString targetId) && targetId.Length == NodeID.Size)
            {
                query = new FindNodeQuery(new TransactionID(transactionId), new NodeID(nodeId), new NodeID(targetId));
                if (arguments.TryGetValue("want", out BList wantList))
                {
                    if (wantList.Contains(new BString("n4")))
                    {
                        query.Want |= Want.IPv4Nodes;
                    }
                    if (wantList.Contains(new BString("n6")))
                    {
                        query.Want |= Want.IPv6Nodes;
                    }
                }
                return(true);
            }

            query = null;
            return(false);
        }
예제 #2
0
        public static bool TryParse(BDictionary message, out AnnouncePeerResponse response)
        {
            if (message.TryGetValue("t", out BString transactionId) && transactionId.Length > 0 &&
                message.TryGetValue("a", out BDictionary arguments) &&
                arguments.TryGetValue("id", out BString nodeId) && nodeId.Length == NodeID.Size)
            {
                response = new AnnouncePeerResponse(new TransactionID(transactionId), new NodeID(nodeId));
                return(true);
            }

            response = null;
            return(false);
        }
예제 #3
0
        public static bool TryParse(BDictionary message, out PingQuery query)
        {
            if (message.Contains("q", new BString("ping")) &&
                message.TryGetValue("t", out BString transactionId) && transactionId.Length > 0 &&
                message.TryGetValue("a", out BDictionary arguments) &&
                arguments.TryGetValue("id", out BString nodeId) && nodeId.Length == NodeID.Size)
            {
                query = new PingQuery(new TransactionID(transactionId), new NodeID(nodeId));
                return(true);
            }

            query = null;
            return(false);
        }
예제 #4
0
        public static bool TryParse(BDictionary message, out ErrorMessage error)
        {
            if (message.TryGetValue("t", out BString transactionId) && transactionId.Length > 0 &&
                message.TryGetValue("e", out BList errorList) && errorList.Count >= 2 &&
                errorList[0] is BInteger errorCode && errorCode >= 201 && errorCode <= 204 &&
                errorList[1] is BString errorMessage)
            {
                error = new ErrorMessage(new TransactionID(transactionId), (ErrorCode)errorCode.Value, errorMessage);
                return(true);
            }

            error = null;
            return(false);
        }
예제 #5
0
        public static MessageType TryParseMessage(byte[] messageBytes, out BDictionary message)
        {
            if (BObject.TryParse(messageBytes, out BObject bObject))
            {
                if (bObject is BDictionary dictionary)
                {
                    message = dictionary;
                    if (message.TryGetValue("y", out BString type))
                    {
                        if (!message.ContainsKey <BString>("t"))
                        {
                            return(MessageType.Invalid);
                        }

                        switch (type.Text)
                        {
                        case "q": return(MessageType.Query);

                        case "r": return(MessageType.Response);

                        case "e": return(MessageType.Error);

                        default: return(MessageType.Unknown);
                        }
                    }
                }
            }

            message = null;
            return(MessageType.Invalid);
        }
예제 #6
0
        public static bool TryParse(BDictionary message, out FindNodeResponse response)
        {
            response = null;

            if (message.TryGetValue("t", out BString transactionId) && transactionId.Length > 0 &&
                message.TryGetValue("a", out BDictionary arguments) &&
                arguments.TryGetValue("id", out BString nodeId) && nodeId.Length == NodeID.Size)
            {
                IPv4Node[] nodes  = null;
                IPv6Node[] nodes6 = null;

                if (arguments.TryGetValue("nodes", out BString nodeBytes))
                {
                    if (!IPv4Node.TryParseCompactNodeInfos(nodeBytes.Bytes, out nodes))
                    {
                        return(false);
                    }
                }
                if (arguments.TryGetValue("nodes6", out BString node6Bytes))
                {
                    if (!IPv6Node.TryParseCompactNodeInfos(nodeBytes.Bytes, out nodes6))
                    {
                        return(false);
                    }
                }

                if (nodes != null)
                {
                    if (nodes6 != null)
                    {
                        response = new FindNodeResponse(new TransactionID(transactionId), new NodeID(nodeId), nodes, nodes6);
                    }
                    else
                    {
                        response = new FindNodeResponse(new TransactionID(transactionId), new NodeID(nodeId), nodes);
                    }
                }
                else if (nodes6 != null)
                {
                    response = new FindNodeResponse(new TransactionID(transactionId), new NodeID(nodeId), nodes6);
                }
            }

            return(response != null);
        }
예제 #7
0
        public static bool TryParse(BDictionary message, out GetPeersQuery query)
        {
            if (message.Contains("q", new BString("get_peers")) &&
                message.TryGetValue("t", out BString transactionId) && transactionId.Length > 0 &&
                message.TryGetValue("a", out BDictionary arguments) &&
                arguments.TryGetValue("id", out BString nodeId) && nodeId.Length == NodeID.Size &&
                arguments.TryGetValue("info_hash", out BString infoHash) && infoHash.Length == InfoHash.Size)
            {
                query = new GetPeersQuery(new TransactionID(transactionId), new NodeID(nodeId), new InfoHash(infoHash));
                if (arguments.TryGetValue("want", out BList wantList))
                {
                    if (wantList.Contains(new BString("n4"))) query.Want |= Want.IPv4Nodes;
                    if (wantList.Contains(new BString("n6"))) query.Want |= Want.IPv6Nodes;
                }
                return true;
            }

            query = null;
            return false;
        }
예제 #8
0
        public static bool TryParse(BDictionary message, out AnnouncePeerQuery query)
        {
            if (message.Contains("q", new BString("announce_peer")) &&
                message.TryGetValue("t", out BString transactionId) && transactionId.Length > 0 &&
                message.TryGetValue("a", out BDictionary arguments) &&
                arguments.TryGetValue("id", out BString nodeId) && nodeId.Length == NodeID.Size &&
                arguments.TryGetValue("info_hash", out BString infoHash) && infoHash.Length == InfoHash.Size &&
                arguments.TryGetValue("token", out BString token) && token.Length > 0 &&
                arguments.TryGetValue("port", out BInteger port) && port.Value >= 0 && port.Value < 65536)
            {
                bool impliedPort = false;
                if (arguments.TryGetValue("implied_port", out BInteger impliedPortValue))
                {
                    impliedPort = impliedPortValue.Value == 1;
                }

                query = new AnnouncePeerQuery(
                    new TransactionID(transactionId), new NodeID(nodeId), new InfoHash(infoHash), new PeerToken(token), (int)port.Value, impliedPort);
                return(true);
            }

            query = null;
            return(false);
        }
예제 #9
0
        public static QueryType TryGetQuery(BDictionary message, out Query query)
        {
            if (message.TryGetValue("q", out BString type))
            {
                switch (type.Text)
                {
                case "ping":
                    if (PingQuery.TryParse(message, out PingQuery pingQuery))
                    {
                        query = pingQuery;
                        return(QueryType.ping);
                    }
                    break;

                case "find_node":
                    if (FindNodeQuery.TryParse(message, out FindNodeQuery findNodeQuery))
                    {
                        query = findNodeQuery;
                        return(QueryType.find_node);
                    }
                    break;

                case "get_peers":
                    if (GetPeersQuery.TryParse(message, out GetPeersQuery getPeersQuery))
                    {
                        query = getPeersQuery;
                        return(QueryType.get_peers);
                    }
                    break;

                case "announce_peer":
                    if (AnnouncePeerQuery.TryParse(message, out AnnouncePeerQuery announcePeerQuery))
                    {
                        query = announcePeerQuery;
                        return(QueryType.announce_peer);
                    }
                    break;

                default:
                    query = null;
                    return(QueryType.Unknown);
                }
            }

            query = null;
            return(QueryType.Invalid);
        }
예제 #10
0
        public static bool TryGetNonBlankString(this BDictionary d, string key, out string s)
        {
            if (!(d.TryGetValue(key, out IBObject op) && op is BString bs))
            {
                s = null;
                return(false);
            }

            var tmp = bs.ToString();

            if (!string.IsNullOrWhiteSpace(tmp))
            {
                s = tmp;
                return(true);
            }
            else
            {
                s = null;
                return(false);
            }
        }
예제 #11
0
        public static bool TryParse(BDictionary message, out GetPeersResponse response)
        {
            response = null;

            if (message.TryGetValue("t", out BString transactionId) && transactionId.Length > 0 &&
                message.TryGetValue("a", out BDictionary arguments) &&
                arguments.TryGetValue("id", out BString nodeId) && nodeId.Length == NodeID.Size &&
                arguments.TryGetValue("token", out BString token) && token.Length > 0)
            {
                if (arguments.TryGetValue("values", out BList values))
                {
                    PeerContact[] peers = new PeerContact[values.Count];
                    for (int i = 0; i < peers.Length; i++)
                    {
                        BObject value = values[i];
                        if (value is BString peer)
                        {
                            if (peer.Length == IPv4PeerContact.CompactInfoSize)
                            {
                                peers[i] = new IPv4PeerContact(peer);
                            }
                            else if (peer.Length == IPv6PeerContact.CompactInfoSize)
                            {
                                peers[i] = new IPv6PeerContact(peer);
                            }
                            else
                            {
                                return(false);
                            }
                        }
                        else
                        {
                            return(false);
                        }
                    }
                    response = new GetPeersResponse(new TransactionID(transactionId), new NodeID(nodeId), new PeerToken(token), peers);
                }
                else
                {
                    IPv4Node[] nodes  = null;
                    IPv6Node[] nodes6 = null;

                    if (arguments.TryGetValue("nodes", out BString nodeBytes))
                    {
                        if (!IPv4Node.TryParseCompactNodeInfos(nodeBytes.Bytes, out nodes))
                        {
                            return(false);
                        }
                    }
                    if (arguments.TryGetValue("nodes6", out BString node6Bytes))
                    {
                        if (!IPv6Node.TryParseCompactNodeInfos(nodeBytes.Bytes, out nodes6))
                        {
                            return(false);
                        }
                    }

                    if (nodes != null)
                    {
                        if (nodes6 != null)
                        {
                            response = new GetPeersResponse(new TransactionID(transactionId), new NodeID(nodeId), new PeerToken(token), nodes, nodes6);
                        }
                        else
                        {
                            response = new GetPeersResponse(new TransactionID(transactionId), new NodeID(nodeId), new PeerToken(token), nodes);
                        }
                    }
                    else if (nodes6 != null)
                    {
                        response = new GetPeersResponse(new TransactionID(transactionId), new NodeID(nodeId), new PeerToken(token), nodes6);
                    }
                }
            }
            return(response != null);
        }
예제 #12
0
        async Task HandleVar_Execute_Internal(string id, BDictionary msg, bool expectOne = false, bool rawResults = false)
        {
            if (!msg.TryGetValue("args", out var beArgs) || !(beArgs is BString beArgsStr))
            {
                await SendException(id, $"Missing required \"args\" argument.");

                return;
            }

            IReadOnlyDictionary <string, JToken> argMap;

            try {
                argMap = JsonConvert.DeserializeObject <IList <IReadOnlyDictionary <string, JToken> > >(beArgsStr.ToString()).First();
            } catch (Exception ex) {
                await SendException(id, $"Couldn't deserialize json payload. Expected a map. Error: {ex.Message}");

                return;
            }

            if (!argMap.TryGetNonBlankString("connection-string", out var connStr))
            {
                await SendException(id, $"Missing required \"connection-string\" argument.");

                return;
            }

            if (!argMap.TryGetNonBlankString("command-text", out var commandText))
            {
                await SendException(id, $"Missing required \"command-text\" argument.");

                return;
            }

            try {
                using (var conn = new SqlConnection(connStr))
                    using (var cmd = conn.CreateCommand()) {
                        await conn.OpenAsync();

                        cmd.CommandText = commandText;

                        if (argMap.TryGetValue("command-type", out JToken commandTypeTok) &&
                            commandTypeTok.Type != JTokenType.Null)
                        {
                            if (commandTypeTok.Type != JTokenType.String)
                            {
                                await SendException(id, $"Expected string. Failing key: \"$.command-type\"");

                                return;
                            }
                            var commandType = commandTypeTok.Value <string>();
                            switch (commandType)
                            {
                            case "stored-procedure":
                                cmd.CommandType = System.Data.CommandType.StoredProcedure;
                                break;

                            case "text":
                                break; // This is the default

                            default:
                                await SendException(id, $"Expected \"stored-procedure\" | \"text\". Failing key: \"$.command-type\"");

                                return;
                            }
                        }

                        if (argMap.TryGetValue("parameters", out JToken paramTok) &&
                            paramTok is JObject paramObj)
                        {
                            foreach (var item in paramObj)
                            {
                                if (!(item.Value is JValue v))
                                {
                                    await SendException(id, $"Can only accept simple values (integers, strings, etc) for parameters. Failing key: \"$.parameters.{item.Key}\"");

                                    return;
                                }
                                cmd.Parameters.AddWithValue(item.Key, v.Value);
                            }
                        }

                        var results = new List <object>();

                        bool multiResultSet;
                        argMap.TryGetBool("multi-rs", out multiResultSet); // same key as next.jdbc

                        using (var rdr = await cmd.ExecuteReaderAsync()) {
                            do
                            {
                                var fieldCount = rdr.FieldCount;
                                var rs         = new ResultSet {
                                    columns =
                                        Enumerable.Range(0, fieldCount)
                                        .Select(i => rdr.GetName(i))
                                        .ToArray()
                                };

                                var isJson = rs.columns.Length == 1 && rs.columns[0] == "JSON_F52E2B61-18A1-11d1-B105-00805F49916B";
                                if (isJson)
                                {
                                    var sb = new StringBuilder();
                                    while (rdr.Read())
                                    {
                                        sb.Append(rdr.GetString(0));
                                    }
                                    if (expectOne || !multiResultSet)
                                    {
                                        await SendResult(id, sb.ToString(), isJson : true);

                                        return;
                                    }
                                    else
                                    {
                                        // @PERF - Think of a way to eliminate deserialize -> serialize for this case
                                        var obj = ParseJson(sb.ToString());
                                        results.Add(obj);
                                    }
                                }
                                else
                                {
                                    var rows = rs.rows = new List <object[]>();
                                    while (rdr.Read())
                                    {
                                        var row = new object[fieldCount];
                                        for (int i = 0; i < fieldCount; i++)
                                        {
                                            rdr.GetValues(row);
                                        }
                                        rows.Add(row);
                                    }
                                    if (expectOne)
                                    {
                                        if (rows.Count > 0)
                                        {
                                            await SendResult(id, ResultSet2DictArray(rs)[0]);
                                        }
                                        else
                                        {
                                            await SendResult(id, null);
                                        }
                                        return;
                                    }
                                    results.Add(rawResults ? (object)rs : ResultSet2DictArray(rs));
                                }
                            } while (rdr.NextResult() && multiResultSet);
                        }

                        object result = null;
                        if (rawResults || multiResultSet)
                        {
                            result = results;
                        }
                        else if (results.Count > 0)
                        {
                            result = results[0];
                        }
                        await SendResult(id, result);
                    }
            } catch (Exception ex) {
                await SendException(id, ex.Message);
            }
        }