diff --git a/src/core/p-net.c b/src/core/p-net.c index d32d37ebe9..5c4389ffe2 100644 --- a/src/core/p-net.c +++ b/src/core/p-net.c @@ -42,22 +42,99 @@ enum Transport_Types { /*********************************************************************** ** -*/ static void Ret_Query_Net(REBSER *port, REBREQ *sock, REBVAL *ret) +*/ static REBOOL Set_Net_Mode_Value(REBREQ *sock, REBCNT mode, REBVAL *ret) +/* +** Set a value with net data according specified mode +** +***********************************************************************/ +{ + switch (mode) { + case SYM_REMOTE_IP: + Set_Tuple(ret, (REBYTE *)&sock->net.remote_ip, 4); + break; + case SYM_REMOTE_PORT: + SET_INTEGER(ret, sock->net.remote_port); + break; + case SYM_LOCAL_IP: + Set_Tuple(ret, (REBYTE *)&sock->net.local_ip, 4); + break; + case SYM_LOCAL_PORT: + SET_INTEGER(ret, sock->net.local_port); + break; + default: + return FALSE; + } + return TRUE; +} + +/*********************************************************************** +** +*/ static void Ret_Query_Net(REBSER *port, REBREQ *sock, REBVAL *ret, REBVAL *info) /* ***********************************************************************/ { - REBVAL *info = In_Object(port, STD_PORT_SCHEME, STD_SCHEME_INFO, 0); REBSER *obj; + REBVAL *val; + + if (IS_WORD(info)) { + if (!Set_Net_Mode_Value(sock, VAL_WORD_CANON(info), ret)) + Trap1(RE_INVALID_ARG, info); + } + else if (IS_BLOCK(info)) { + // example: + // query/mode port [remote-ip remote-port] ;== [127.0.0.1 1234] + // or: + // query/mode port [remote-ip: remote-port:] ;== [remote-ip: 127.0.0.1 remote-port: 1234] + // or combined: + // query/mode file [remote-ip: remote-port] ;== [remote-ip: 127.0.0.1 1234] + // When not supported word is used, if will throw an error + + REBSER *values = Make_Block(2 * BLK_LEN(VAL_SERIES(info))); + REBVAL *word = VAL_BLK_DATA(info); + for (; NOT_END(word); word++) { + if (ANY_WORD(word)) { + if (IS_SET_WORD(word)) { + // keep the set-word in result + val = Append_Value(values); + *val = *word; + VAL_SET_LINE(val); + } + val = Append_Value(values); + if (!Set_Net_Mode_Value(sock, VAL_WORD_CANON(word), val)) + Trap1(RE_INVALID_ARG, word); + } + else Trap1(RE_INVALID_ARG, word); + } + Set_Series(REB_BLOCK, ret, values); + } + else { + //@@ oldes: is returning object really still needed? + info = In_Object(port, STD_PORT_SCHEME, STD_SCHEME_INFO, 0); - if (!info || !IS_OBJECT(info)) Trap_Port(RE_INVALID_SPEC, port, -10); + if (!info || !IS_OBJECT(info)) { + Trap_Port(RE_INVALID_SPEC, port, -10); + return; // prevents compiler's warning + } - obj = CLONE_OBJECT(VAL_OBJ_FRAME(info)); + obj = CLONE_OBJECT(VAL_OBJ_FRAME(info)); - SET_OBJECT(ret, obj); - Set_Tuple(OFV(obj, STD_NET_INFO_LOCAL_IP), (REBYTE*)&sock->net.local_ip, 4); - Set_Tuple(OFV(obj, STD_NET_INFO_REMOTE_IP), (REBYTE*)&sock->net.remote_ip, 4); - SET_INTEGER(OFV(obj, STD_NET_INFO_LOCAL_PORT), sock->net.local_port); - SET_INTEGER(OFV(obj, STD_NET_INFO_REMOTE_PORT), sock->net.remote_port); + SET_OBJECT(ret, obj); + Set_Tuple(OFV(obj, STD_NET_INFO_LOCAL_IP), (REBYTE *)&sock->net.local_ip, 4); + Set_Tuple(OFV(obj, STD_NET_INFO_REMOTE_IP), (REBYTE *)&sock->net.remote_ip, 4); + SET_INTEGER(OFV(obj, STD_NET_INFO_LOCAL_PORT), sock->net.local_port); + SET_INTEGER(OFV(obj, STD_NET_INFO_REMOTE_PORT), sock->net.remote_port); + } +} + +/*********************************************************************** +** +*/ void Ret_Net_Modes(REBSER *port, REBVAL *ret) +/* +** Sets value with block of possible net mode names +** +***********************************************************************/ +{ + Set_Block(ret, Get_Object_Words(In_Object(port, STD_PORT_SCHEME, STD_SCHEME_INFO, 0))); } @@ -264,7 +341,12 @@ enum Transport_Types { case A_QUERY: // Get specific information - the scheme's info object. // Special notation allows just getting part of the info. - Ret_Query_Net(port, sock, D_RET); + refs = Find_Refines(ds, ALL_QUERY_REFS); + if ((refs & AM_QUERY_MODE) && IS_NONE(D_ARG(ARG_QUERY_FIELD))) { + Ret_Net_Modes(port, D_RET); + return R_RET; + } + Ret_Query_Net(port, sock, D_RET, D_ARG(ARG_QUERY_FIELD)); break; case A_OPENQ: diff --git a/src/tests/test-udp-server.r3 b/src/tests/test-udp-server.r3 index 2025a483de..2d307b08d0 100644 --- a/src/tests/test-udp-server.r3 +++ b/src/tests/test-udp-server.r3 @@ -14,7 +14,7 @@ stdout: system/ports/output udp-server/awake: func [event /local port str] [ port: event/port - print ["[UDP Server] event:" event/type] + print ["[UDP Server] event:" event/type "from ip:" query/mode port 'remote-ip ] switch event/type [ read [ str: to string! port/data diff --git a/src/tests/units/port-test.r3 b/src/tests/units/port-test.r3 index 2b90f8de45..f2f1b1d5af 100644 --- a/src/tests/units/port-test.r3 +++ b/src/tests/units/port-test.r3 @@ -583,6 +583,25 @@ if all [ ===end-group=== +===start-group=== "TCP" + --test-- "query net info" + ;@@ https://github.com/Oldes/Rebol-issues/issues/1712 + port: open tcp://8.8.8.8:80 + --assert [local-ip local-port remote-ip remote-port] = query/mode port none + --assert 0.0.0.0 = query/mode port 'local-ip + --assert 0 = query/mode port 'local-port + --assert 0.0.0.0 = query/mode port 'remote-ip + --assert 80 = query/mode port 'remote-port + --assert all [ + port? wait [port 1] ;= wait for lookup, so remote-ip is resolved + 8.8.8.8 = query/mode port 'remote-ip + [80 8.8.8.8] = query/mode port [remote-port remote-ip] + [local-ip: 0.0.0.0 local-port: 0] = query/mode port [local-ip: local-port:] + ] + try [close port] +===end-group=== + + ===start-group=== "SYSTEM" --test-- "query system://" ;@@ https://github.com/Oldes/Rebol-issues/issues/1373