How to I get the IP address of the client in Deno?
I have created a test server using the standard http library but I can't figure out a way to extract client's IP.
I need that as a security feature for preventing multiple submissions.
In NodeJS/Express there is an ip property of the request object that does the same.
req.ip gives the thing I want in Express but what is it's equivalent in Deno?
My code is:
import { serve } from "https://deno.land/std#0.125.0/http/server.ts";
serve(
(req) => {
console.log(/* the client IP */);
return new Response("hello");
},
{ port: 8080 }
);
Is there any other work-around to prevent multiple access from the same device?
Thanks
To do this in a type-safe way is a little complicated because of the way that serve is typed. First, I'll show you an example of how to do it, then I'll explain the types afterward.
Example
example.ts:
import {
serve,
type ConnInfo,
type Handler,
type ServeInit,
} from 'https://deno.land/std#0.125.0/http/server.ts';
function assertIsNetAddr (addr: Deno.Addr): asserts addr is Deno.NetAddr {
if (!['tcp', 'udp'].includes(addr.transport)) {
throw new Error('Not a network address');
}
}
function getRemoteAddress (connInfo: ConnInfo): Deno.NetAddr {
assertIsNetAddr(connInfo.remoteAddr);
return connInfo.remoteAddr;
}
const handler: Handler = (request, connInfo) => {
const {hostname, port} = getRemoteAddress(connInfo);
const message = `You connected from the following address: ${hostname}`;
return new Response(message);
};
const init: ServeInit = {port: 8080};
serve(handler, init);
console.log(`Listening on port ${init.port}...\nUse ctrl+c to stop`);
Types
Looking at the documentation for the serve function, you can see that it accepts two parameters: a callback of type Handler, and some options of type ServeInit:
async function serve(handler: Handler, options?: ServeInit): Promise<void>;
The Handler callback accepts two parameters: a Request, and an object of type ConnInfo:
type Handler = (request: Request, connInfo: ConnInfo) => Response | Promise<Response>;
ConnInfo looks like this:
interface ConnInfo {
readonly localAddr: Deno.Addr;
readonly remoteAddr: Deno.Addr;
}
The part that should have the remote IP address (technically, it's the remote hostname, but it's very likely to be an IP address unless you have configured custom DNS settings in your server environment) is the object at connInfo.remoteAddr, which (you can see above) is of type Deno.Addr, which looks like this:
// in the Deno namespace
type Addr = NetAddr | UnixAddr;
This is where it becomes complicated. Deno.Addr is a discriminated union of Deno.NetAddr and Deno.UnixAddr (which means that it could be either one), and the property transport is used to discriminate between the two.
// in the Deno namespace
interface NetAddr {
hostname: string;
port: number;
transport: "tcp" | "udp";
}
interface UnixAddr {
path: string;
transport: "unix" | "unixpacket";
}
A net address has hostname property (the value of which would be the IP address) and a port property, while a unix address has a path property.
The listener which is created internally to support the server is actually only listening on TCP, so I think it's safe to assume that the remote address will be a net address. However, because the type signature of the Handler callback parameter in the serve function doesn't make this explicit (although it should!), TypeScript doesn't know that.
So, it's left up to you as the programmer to make sure that the address is actually a net address before you can access properties that would be on a net address (instead of a unix address) in a type-safe way. That's where the type assertion function assertIsNetAddr comes into play. (A type assertion performs a runtime test which results in a "guarantee" of a condition to the compiler: by throwing an exception if the condition can't be guaranteed.) Because you as the programmer already know more than the TypeScript compiler (that the address is on TCP and will be a net address), you can assert that the address is indeed a net address. Then the compiler will allow you use the address as a net address.
If you want to do something besides throwing an Error in the case that the address is not a net address: instead of an assertion function, you can use a type predicate as a condition in your code.
Here is a link to the TypeScript Playground where I've created a playground with the types used in my example, so you can explore/experiment.
Finally, (this is not type-safe) if you just want to use the value without the checks (because you've done your research and are confident that you will never handle a non-TCP connection, you can simply use a type assertion:
const handler: Handler = (request, connInfo) => {
const {hostname, port} = connInfo.remoteAddr as Deno.NetAddr;
const message = `You connected from the following address: ${hostname}`;
return new Response(message);
};
Closed. This question is not reproducible or was caused by typos. It is not currently accepting answers.
This question was caused by a typo or a problem that can no longer be reproduced. While similar questions may be on-topic here, this one was resolved in a way less likely to help future readers.
Closed 2 years ago.
Improve this question
I am implementing an interface to an embedded device which exposes its hardware configuration via a dbus API.
At the moment I work out the access to the hardware I/O-pins of the device. While configuring and reading/writing those pins works already as expected, I have problems to properly connect the PropertiesChanged signal for those input pins to a slot in my qt application. That signal is notifying listeners of changes to the present input value at that very pin.
When whatched via dbus-monitor the signal for example looks like this:
signal sender=:1.2 -> dest=(null destination) serial=1023 path=/com/actia/platform/io/freq_in1_std; interface=org.freedesktop.DBus.Properties; member=PropertiesChanged
string "com.actia.platform.io.digital_input"
array [
dict entry(
string "InputValue"
variant int32 17857
)
]
array [
]
which represents the value of an applied frequency of 1.7857 kHz.
I connect to the signal like so:
if (QDBusConnection::sessionBus().connect("com.actia.platform.io", "/com/actia/platform/io/freq_in1_std",
"org.freedesktop.DBus.Properties", "PropertiesChanged", this,
SLOT(propertyChanged(QString, QVariantMap, QStringList)))) {
qDebug() << "PropertiesChanged signal connected successfully to slot";
} else {
qDebug() << "PropertiesChanged signal connection was not successful";
}
and the connected slot looks like:
void MyClass::propertyChanged(QString name, QVariantMap map, QStringList list)
{
qDebug() << QString("properties of interface %1 changed").arg(name);
for (QVariantMap::const_iterator it = map.cbegin(), end = map.cend(); it != end; ++it) {
qDebug() << "property: " << it.key() << " value: " << it.value();
}
for (const auto& element : list) {
qDebug() << "list element: " << element;
}
}
I see that the connection is done successfully but apparently something seems not to be right about the signature, I assume. Because I never see that slot called.
Here is an excerpt of the debug output with QDBUS_DEBUG=1 of a little example application class, where I instanciate one input and one output pin where I connect the PropertiesChanged signal and then access some of the dbus methods and properties manually, before leaving it idling to wait for the signal to catch. I commented that debug log a bit. After some time, when the signal on the dbus has been fired several times, I quit the application.
### application.debug: start of initialization before issuing QCoreApplication::exec()...
### application.debug: creating a digital out pin...
// comment on the logs: The folloiwing 6 lines of debug output originate of instanciating the matching dbus proxy that has been generated by qdbusxml2cpp
QDBusConnectionPrivate(0x747021d0) : connected successfully
QDBusConnectionPrivate(0x747021d0) got message (signal): QDBusMessage(type=Signal, service="org.freedesktop.DBus", path="/org/freedesktop/DBus", interface="org.freedesktop.DBus", member="NameAcquired", signature="s", contents=(":1.1464") )
QDBusConnectionPrivate(0x747021d0) delivery is suspended
QDBusConnectionPrivate(0x747021d0) Adding rule: "type='signal',sender='org.freedesktop.DBus',interface='org.freedesktop.DBus',member='NameOwnerChanged',arg0='com.actia.platform.io'"
QDBusConnectionPrivate(0x747021d0) sending message: QDBusMessage(type=MethodCall, service="org.freedesktop.DBus", path="/org/freedesktop/DBus", interface="org.freedesktop.DBus", member="GetNameOwner", signature="", contents=("com.actia.platform.io") )
QDBusConnectionPrivate(0x747021d0) got message reply: QDBusMessage(type=MethodReturn, service="org.freedesktop.DBus", signature="s", contents=(":1.2") )
### application.debug: Connecting the PropertiesChanged signal for the created pin...
QDBusConnectionPrivate(0x74710460) : connected successfully
QDBusConnectionPrivate(0x74710460) got message (signal): QDBusMessage(type=Signal, service="org.freedesktop.DBus", path="/org/freedesktop/DBus", interface="org.freedesktop.DBus", member="NameAcquired", signature="s", contents=(":1.28") )
QDBusConnectionPrivate(0x74710460) delivery is suspended
QDBusConnectionPrivate(0x74710460) Adding rule: "type='signal',sender='com.actia.platform.io',path='/com/actia/platform/io/dout1',interface='org.freedesktop.DBus.Properties',member='PropertiesChanged'"
QDBusConnectionPrivate(0x74710460) sending message: QDBusMessage(type=MethodCall, service="org.freedesktop.DBus", path="/org/freedesktop/DBus", interface="org.freedesktop.DBus", member="GetNameOwner", signature="", contents=("com.actia.platform.io") )
QDBusConnectionPrivate(0x74710460) got message reply: QDBusMessage(type=Error, service="org.freedesktop.DBus", error name="org.freedesktop.DBus.Error.NameHasNoOwner", error message="Could not get owner of name 'com.actia.platform.io': no such name", signature="s", contents=("Could not get owner of name 'com.actia.platform.io': no such name") )
QDBusConnectionPrivate(0x74710460) Watching service "com.actia.platform.io" for owner changes (current owner: "" )
### application.debug: PropertiesChanged signal connected successfully to slot
### application.debug: creating a digital in pin...
// comment on the logs: The following 2 lines of debug output originate of instanciating the matching dbus proxy that has been generated by qdbusxml2cpp
QDBusConnectionPrivate(0x747021d0) sending message: QDBusMessage(type=MethodCall, service="org.freedesktop.DBus", path="/org/freedesktop/DBus", interface="org.freedesktop.DBus", member="GetNameOwner", signature="", contents=("com.actia.platform.io") )
QDBusConnectionPrivate(0x747021d0) got message reply: QDBusMessage(type=MethodReturn, service="org.freedesktop.DBus", signature="s", contents=(":1.2") )
### application.debug: Connecting the PropertiesChanged signal for the created pin...
QDBusConnectionPrivate(0x74710460) Adding rule: "type='signal',sender='com.actia.platform.io',path='/com/actia/platform/io/freq_in1_std',interface='org.freedesktop.DBus.Properties',member='PropertiesChanged'"
### application.debug: PropertiesChanged signal connected successfully to slot
### application.debug: success setting pin modes for the digital out pin to pwm generation: true
// comment on the logs: setting a value on an output pin now
QDBusConnectionPrivate(0x747021d0) sending message: QDBusMessage(type=MethodCall, service="com.actia.platform.io", path="/com/actia/platform/io/dout1", interface="com.actia.platform.io.digital_output", member="SetValue", signature="", contents=(200, 80) )
QDBusConnectionPrivate(0x747021d0) got message reply: QDBusMessage(type=MethodReturn, service=":1.2", signature="", contents=() )
### application.debug: success setting pwm of 20 Hz at 80% duty cycle: true
// comment on the logs: reading back the properties for the pins to verify
QDBusConnectionPrivate(0x747021d0) sending message: QDBusMessage(type=MethodCall, service="com.actia.platform.io", path="/com/actia/platform/io/dout1", interface="org.freedesktop.DBus.Properties", member="Get", signature="", contents=("com.actia.platform.io.digital_output", "OutputFrequency") )
QDBusConnectionPrivate(0x747021d0) got message reply: QDBusMessage(type=MethodReturn, service=":1.2", signature="v", contents=([Variant(int): 200]) )
QDBusConnectionPrivate(0x747021d0) sending message: QDBusMessage(type=MethodCall, service="com.actia.platform.io", path="/com/actia/platform/io/dout1", interface="org.freedesktop.DBus.Properties", member="Get", signature="", contents=("com.actia.platform.io.digital_output", "OutputRatio") )
QDBusConnectionPrivate(0x747021d0) got message reply: QDBusMessage(type=MethodReturn, service=":1.2", signature="v", contents=([Variant(int): 80]) )
### application.debug: pwm backread frequency 20, duty cycle 80
// comment on the logs: setting the mode of a digital input pin to read a frequency instead a logical 0 or 1
QDBusConnectionPrivate(0x747021d0) sending message: QDBusMessage(type=MethodCall, service="com.actia.platform.io", path="/com/actia/platform/io/freq_in1_std", interface="com.actia.platform.io.digital_input", member="SetInputType", signature="", contents=(2) )
QDBusConnectionPrivate(0x747021d0) got message reply: QDBusMessage(type=MethodReturn, service=":1.2", signature="", contents=() )
### application.debug: setting pin modes of the digital in pin to read a frequency: true
// comment on the logs: reading the currently applied frequency from the pin now
QDBusConnectionPrivate(0x747021d0) sending message: QDBusMessage(type=MethodCall, service="com.actia.platform.io", path="/com/actia/platform/io/freq_in1_std", interface="org.freedesktop.DBus.Properties", member="Get", signature="", contents=("com.actia.platform.io.digital_input", "InputValue") )
QDBusConnectionPrivate(0x747021d0) got message reply: QDBusMessage(type=MethodReturn, service=":1.2", signature="v", contents=([Variant(int): 17361]) )
### application.debug: reading the current frequency from digital input: 1736.1 Hz
### application.debug: end of actual code during initialization, now issuing QCoreApplication::exec()...
QDBusConnectionPrivate(0x747021d0) dequeueing message QDBusMessage(type=Signal, service="org.freedesktop.DBus", path="/org/freedesktop/DBus", interface="org.freedesktop.DBus", member="NameAcquired", signature="s", contents=(":1.1464") )
QDBusConnectionPrivate(0x74710460) dequeueing message QDBusMessage(type=Signal, service="org.freedesktop.DBus", path="/org/freedesktop/DBus", interface="org.freedesktop.DBus", member="NameAcquired", signature="s", contents=(":1.28") )
[...] program running, waiting for signals
### application.debug: QCoreApplication::quit()
QDBusConnectionPrivate(0x74710460) Removing rule: "type='signal',sender='com.actia.platform.io',path='/com/actia/platform/io/freq_in1_std',interface='org.freedesktop.DBus.Properties',member='PropertiesChanged'"
QDBusConnectionPrivate(0x74710460) Removing rule: "type='signal',sender='com.actia.platform.io',path='/com/actia/platform/io/dout1',interface='org.freedesktop.DBus.Properties',member='PropertiesChanged'"
QDBusConnectionPrivate(0x747021d0) Disconnected
QDBusConnectionPrivate(0x74710460) Disconnected
I read a huge amount of advice that I found on SO or the QT forums about connecting to the PropertiesChanged signal and tried some suggestions from there but to no avail. There must be some signature mismatch which I am not aware of. However I peeked in the code of some dbus applications like networkmanager-qt and they are using the three arguments that I also use in my signature: QString,QVariantMap,QStringList.
I'm stuck now and hope that anyone has another hint that I could follow.
Thanks in advance.
Well, I really do not know why. But when I tried the exact code above again with a fresh from-source qt build (of the same version as before), it worked. So I consider this solved for now.
My app will have an array of serviceUUIDs with which to discover selected peripherals. Once a peripheral from that set is discovered, how do I then determine which serviceUUID it has/had to allow it to be discovered? The UUID of the peripheral's identifier seems to be different than the serviceUUID I gave it in my test code.
You can read the detected service UUIDs out of the advertisement, but they might come in two places depending on whether the advertisement originated from backgrounded iOS devices (which transmit in the "overflow area").
Try something like this to get the list of service UUIDs from both places:
func centralManager(_ central: CBCentralManager, didDiscover peripheral: CBPeripheral, advertisementData: [String : Any], rssi RSSI: NSNumber) {
var detectedServiceUuids = advertisementData[CBAdvertisementDataServiceUUIDsKey] as? [CBUUID] ?? []
if let detectedOverflowUuids = advertisementData[CBAdvertisementDataOverflowServiceUUIDsKey] as? [CBUUID] {
detectedServiceUuids.append(contentsOf: detectedOverflowUuids)
}
for detectedServiceUuid in detectedServiceUuids {
print("I detected serviceUuid: \(detectedServiceUuid)")
}
}
I'm trying to connect to a D-Bus signal this way:
bool result = QDBusConnection::systemBus().connect(
"foo.bar", // service
"/foo/bar", // path
"foo.bar", // interface
"SignalSomething",
this,
SLOT(SignalSomethingSlot()));
if( !result )
{
// Why!?
}
QDBusConnection::connect() returns a boolean, how do I get extended error information? If a check QDBusConnection::lastError() it returns no useful information (as QDBusError::isValid() is false).
I had the same issue and it turned out that the slot I connected to had the wrong parameter types. They must match according to Qt's documentation and it looks like connect() verifies that, despite not explicitly mentioned.
Warning: The signal will only be delivered to the slot if the parameters match.
I suggest d-feet to list signals and check their parameter types. dbus-monitor does list signals, paths and such too, but not always the exact type of parameters.
One important observation though: I fixed the issue in my particular case by using different slot parameters than the actual signal has!
I wanted to connect to a com.ubuntu.Upstart0_6 signal mentioned here to detect when the screen in Ubuntu is locked/unlocked. dbusmonitor prints the following and d-feet shows parameters (String, Array of [String])
// dbusmonitor output
signal time=1529077633.579984 sender=:1.0 -> destination=(null destination) serial=809 path=/com/ubuntu/Upstart; interface=com.ubuntu.Upstart0_6; member=EventEmitted
string "desktop-unlock"
array [
]
Hence the signal should be of type
void screenLockChangedUbuntu(QString event, QVector<QString> args) // connect() -> false
This however made connect() return false. The solution was to remove the array parameter from the slot:
void screenLockChangedUbuntu(QString event) // works
I am aware that the array parameter was always empty, but I cannot explain why it only worked when removing it.
You could try these tricks:
1) Set QDBUS_DEBUG environment variable before running your application.
export QDBUS_DEBUG=1
2) Start dbus-monitor to see what's happening on the bus. You may need to set a global policy to be able to eavesdrop system bus depending on your distro.
Update:
Are you sure connecting to the system bus succeeded? If it fails you should probably check system.conf policy and possibly create own conf in system.d. This post might be helpful.
You could first connect to the system bus with QDBusConnection::connectToBus and check if it succeeded with QDBusConnection::isConnected. Only after that you try to connect to the signal and check if that succeeded.
QDBusConnection bus = QDBusConnection::connectToBus(QDBusConnection::systemBus, myConnectionName);
if (bus.isConnected())
{
if(!bus.connect( ... ))
{
// Connecting to signal failed
}
}
else
{
// Connecting to system bus failed
}
I would like to send a string via a socket to an external display unit via the oracle 11g database
I gather that the character or string first has to be converted to hex and at the end of the string a checksum must be addead (to validate the string to be sent)
Can anyone tell me how a socket connection can be opened and a string can be sent?
Thank you
DECLARE
bt_conn UTL_TCP.connection;
retval BINARY_INTEGER;
l_sequence VARCHAR2 (50) := '#0100010303000118000201001401000201'; --string to be sent
BEGIN
bt_conn :=
UTL_TCP.open_connection (remote_host => '127.0.0.1', --IP of socket to be opened
remote_port => 26665, -- port number of socket
tx_timeout => 15);
DBMS_LOCK.SLEEP(1); -- this is to ensure a slight pause once opening the connection before --sending the string
retval := UTL_TCP.write_line (bt_conn, l_sequence);
UTL_TCP.flush (bt_conn);
UTL_TCP.close_connection (bt_conn);
EXCEPTION
WHEN OTHERS
THEN
raise_application_error (-20101, SQLERRM);
UTL_TCP.close_connection (bt_conn);
end;
Theoretically you can achieve this by using Java stored procedure - if you grant yourself priv to open a TCP socket from Oracle JVM. But this way the data will be sent regardless on transaction result(commit or rollback). The better solution would to store those strings in some queue table and then withdraw them using some external process.
You can also use DBMS_PIPE.