kirillzyusko / react-native-wifi-p2p

Library that provide access for working with wi-fi direct (p2p) module in android.
174 stars 32 forks source link

Unable to connect [Error: failed to connect to /192.168.49.1 (port 8988) from /192.168.49.1 (port 37003) after 5000ms: isConnected failed: ECONNREFUSED (Connection refused)] #38

Open ghost opened 4 years ago

ghost commented 4 years ago

Repeatedly getting this while using sendMessage() and sendFile(). My code is as follows -

import * as WiFiP2P from 'react-native-wifi-p2p';

export const sendFilesToServer = (macAddr, files) => {
    console.log(files, macAddr);
    files.forEach(file => {
        WiFiP2P.connect(macAddr)
            // Resolve connection details using getConnectionInfo
            // .then(() => WiFiP2P.createGroup())
            .then(() => WiFiP2P.getConnectionInfo())
            .then(() => WiFiP2P.getAvailablePeers())
            // Send file metadata using sendMessage()
            .then(() => console.log(file.name))
            .then(() => {
                console.log('SENDING message');
                return WiFiP2P.sendMessage(file.name);
            })
            // Send file
            .then(() => {
                console.log('SENDING file');
                return WiFiP2P.sendFile(file.uri);
            })
            .catch(err => console.log('Unable to connect', err));
    });
}

export const receiveFromClient = () => {
    console.log('Can receive now');
    // Receive file metadata using receiveMessage()
    WiFiP2P.createGroup()
        .then(() => WiFiP2P.receiveMessage())
        // .then(() => {
        //     return PermissionsAndroid.request(
        //         PermissionsAndroid.PERMISSIONS.WRITE_EXTERNAL_STORAGE,
        //         {
        //             'title': 'Access to write',
        //             'message': 'WRITE_EXTERNAL_STORAGE'
        //         }
        //     )
        // })

        // Receive file and store it based on the metadata
        .then(message => {
            console.log('Received message ', message);
            return WiFiP2P.receiveFile('/storage/emulated/0/Music/', message);
        })
        .catch(err => console.log(err));
}

EDIT : In addition, whenever the server tries to run createGroup(), it always returns with the error as follows { "code" : 2, "message": "Operation failed because the framework is busy and unable to service the request" }

kirillzyusko commented 4 years ago

Hi @c-thun Hm, in fact it looks like a race condition.

You are trying to send multiple files at the same time (that's how forEach works) - it's not correct. In receiveFromClient function you receive only one file.

In case if you want to send multiple files you should do it sequentially: file1 -> file2 -> file3 (only after successful transfer of file1 you start transfering file2).

I hope I gave you an answer on your question why it's not working. Try to rewrite your code and send files sequentially. Feel free to ask other questions if something is not clear :)

ghost commented 4 years ago

So if i try and send one file, it should work, right?

However, that still doesn't seem to explain why calling createGroup() is failing in the receiver side. Also, thanks for pointing that out. I had totally forgotten the race condition issue so will rectify that.

Upon testing with one file only (to prevent for the issue of race condition), I still get the same error. The exact same error.

I can see that sendFile() may have an issue because the file path is something like this "content://com.android.providers.media.documents/document/image%3A217" and you mentioned in another issue that this can be a problem. However, even in this case, sendMessage() should work by commenting out the rest. Also, the server should be able to create a group but that isn't happening either as mentioned above.

Any help, insight, etc would be helpful. I can give you exact logs from whatever source you want so if you need me to provide any such, do ask and I would be happy to provide you the details so that this issue can be fixed

kirillzyusko commented 4 years ago

Hi, @c-thun

However, that still doesn't seem to explain why calling createGroup() is failing in the receiver side.

That would be nice if you can share your logs from adb logcat. Please, attach them as *.txt file.

You described your issue, and I understand what is the problem. And, of course, this problem shouldn't exist. So attaching Android logs (Java) can help me significantly :)

BTW, have you tried to switch you server/client devices? I mean run client code on "server" phone, and "client" code on server device? Merely change roles of devices. In this case you still receive the same error?

ghost commented 4 years ago

I did change the roles of the devices multiple times but it didn't do anything different except for once when it did actually manage to send a message to the other device. Other than that one transmission, it didn't work regardless of which device was client and which was server.

Will attach the ADB Logcat response in a few hours (away from my laptop right now)

ghost commented 4 years ago

Here is the ADB Logcat. Steps done in sequence : -

In addition, for some reason it shows a FINE_LOCATION issue in adb logcat but I have provided both and for FINE_LOCATION in the Manifest and have provided the app with full location access (Allow all the time) after calling the location permission as asked from your code (And it shows that P2P mode can be used, isInitialised: true and startDiscoveringPeers successful output.txt

kirillzyusko commented 4 years ago

As I see from logs the internal variable wifip2pInfo is null. Why are you calling getAvailablePeers?

BTW, I don't see successful execution of getConnectionInfo https://github.com/kirillzyusko/react-native-wifi-p2p/blob/102e00508501ad32aeaca0b651312170c4f129d8/android/src/main/java/io/wifi/p2p/WiFiP2PManagerModule.java#L63

ghost commented 4 years ago

getAvailablePeers() was called only as a debugging step to confirm if it was actually seeing the other device or not. The logcat output after removing the line are attached below. Also, I used console.log(devices) in subscribeOnPeersUpdates() to confirm if there actually are devices nearby. Attaching that as well.

Also, you are right that getConnectionInfo() is failing adb_output.txt Screenshot from 2020-08-19 01-49-20

ghost commented 4 years ago

Trying after reversing the devices, here are the adb logcat files after reversing the devices roles.

Also, I got a doubt. createGroup() always fails as it says that the framework is busy. Could it be because subscribeOnPeersUpdates() is always running in the background and preventing createGroup() from using the WiFiP2P service? If that is the case, I can unsubscribe before calling createGroup() and try

reverse_adb_output.txt

kirillzyusko commented 4 years ago

Also, I got a doubt. createGroup() always fails as it says that the framework is busy. Could it be because subscribeOnPeersUpdates() is always running in the background and preventing createGroup() from using the WiFiP2P service? If that is the case, I can unsubscribe before calling createGroup() and try

I don't think so. In fact I found the same problem. Try to find 01:49:44.409 from previous log. What was this command? createGroup? Have you checked - maybe group already was formed? BTW, what type of debugging do you use? Through WiFi or through USB cable? (If you are debugging/downloading bundle via WiFi - please, try to switch to cable method). I'm asking because I see SoftException from RN straight after the line that I mentioned (It's about WebSockets).

ghost commented 4 years ago

The one on 01:49:44.409 is the output that is caused by problems in the startDiscoveringPeers() method. This one actually would have happened because the app crashed during sendMessage() and upon reload, was not able to even start discovering the peers properly. I needed to force close the app and reload it from scratch to get it working normally. So, this output was post crash

Also, I am using USB cable (that came with the phone's charger) to debug the app. The soft exception would have been due to the crash I suppose.

Also, wherever I have called createGroup(), I have now ensured that on successful creation, it will do a console.log('Successfully created group'). As I have not seen any such outputs on console regarding successful group creation even once, the only thing I can assume is that createGroup() has never run successfully for me.

ghost commented 4 years ago

Any updates?

kirillzyusko commented 4 years ago

One interesting moment:

Calling JS function after bridge has been destroyed: RCTDeviceEventEmitter.emit(["WIFI_P2P:PEERS_UPDATED",{"devices":[{"status":1,"isGroupOwner":false,"secondaryDeviceType":null,"primaryDeviceType":"10-0050F204-5","deviceAddress":"82:58:f8:25:e0:01","deviceName":"Android_819e"}]}])

Why bridge has been destroyed? :) It happens before actual sending.

Another moment:

08-19 01:49:33.109   674  1086 D WifiP2pService: Client:com.meridio is removed
08-19 01:49:33.110   674  1086 D WifiP2pService: Client:com.meridio is removed

Why it removes two times?

In adb reverse:

08-19 01:56:58.512 16570 18232 W ReactNativeJS: Cannot connect to the Metro server.

Why so?

I don't see any direct errors, to be honest... Could you edit your code in node_modules and add more Log.i statements? I don't know why getConnectionInfo failing... Also I don't see Successfully created group.

I know, my answer probably will not help you, since I don't know what is going wrong...

ghost commented 4 years ago

So you mean adding more log statements in react-native-wifi-p2p package?

And yes, I am never able to create group despite following the exact same order that was in your documentation. Can the issue here also be caused by the fact that I'm using a rooted phone with a custom ROM? If yes, then I can retry running the code after reverting the devices to the OEM builds (I'm not sure why this would cause an issue but custom ROMs can sometimes have missing implementations of features)

kirillzyusko commented 4 years ago

So you mean adding more log statements in react-native-wifi-p2p package?

Yes, it may be useful to see, where the errors occur. You can try to wrap the body of getConnectionInfo in try/catch statement and see, what error emerges there. I think it can be useful.

And yes, I am never able to create group despite following the exact same order that was in your documentation. Can the issue here also be caused by the fact that I'm using a rooted phone with a custom ROM? If yes, then I can retry running the code after reverting the devices to the OEM builds (I'm not sure why this would cause an issue but custom ROMs can sometimes have missing implementations of features)

It can be, however I'm not sure...

ghost commented 4 years ago

So it's definitely not due to the custom ROM. I reverted to the stock firmware and it still is not able to create the group. Maybe I can go for the suboptimal solution of connecting via QR codes and then sharing via TCP for now but would have really loved this to work. I'm completely stumped why this doesn't work.

If you feel like, I can open source my app repo and you can take a look? Maybe you'll find some issues over there. Also, if you have time and are willing to collaborate, you could join in as a contributor to the app I'm making. If we can make it work with your API, then it can be a really nice Proof of concept for your library. I'm honestly in a slump right now and any help would be immensely helpful 😢

kirillzyusko commented 4 years ago

@c-thun have you tried use this repo: https://github.com/kirillzyusko/react-native-wifi-p2p-example Maybe you made a mistake in the integration this library into your project? I really want to help you. So, please, try to reproduce your problem using this repo. If you still will not be able to create group even in this repository - I really don't know, how to help you. Maybe only a call/screen-sharing-session with you may help us. I will tell you what you can change and we will see how it affects.

ghost commented 4 years ago

That was one of the first things I did and, if I recall correctly, even then I was not able to create group and it showed the same error even then.

Code 2 : Resource is busy

I can try it once more today but if it doesn't work, I'll probably ask my friends to try my app on their devices (maybe it turns out to be a hardware issue) and the if even that works, I might probably have to just resort to the QR based solution. Thanks a lot for the help though.

kirillzyusko commented 4 years ago

You can read more about error: https://developer.android.com/reference/android/net/wifi/p2p/WifiP2pManager#BUSY It's system Android error. So the search in the internet may also give you some useful insights. Just try to search busy wifi p2p create group in google :) And yes, try on other devices. I hope you will be able to solve this issue.

ghost commented 4 years ago

For sure, will look into it in some time. Do keep the issue open, if there is some update that helps me fix this issue, then I can let you know and hopefully this can help others who face this issue too.

ghost commented 4 years ago

Screenshot from 2020-08-22 03-51-03 So, I managed to overcome the issues of creating group by calling a remove group first. However, this only worked with one device and didn't work with the other (for some weird reason). In addition, while I'm trying to send files, I'm getting this error (attached)

kirillzyusko commented 4 years ago

Good. At least one device now can create group successfully. The error seems to be the same as before. So I have to ask: did you call getConnectionInfo? Was the execution of this function successful?

ghost commented 4 years ago

So, as you can see in the picture, the console output Getting connection info occurs while I'm calling getConnectionInfo() so that's happening successfully (atleast on one device). The error occurs while sending file using sendFile(). Have a look at the modified code and see if you can spot any errors in the flow

import * as WiFiP2P from 'react-native-wifi-p2p';

const sendFiles = (files) => {
    const nextFile = files.shift();

    if (nextFile) {
        console.log('Sending file ', nextFile.name);
        return WiFiP2P.sendMessage(nextFile.name).then(WiFiP2P.sendFile(nextFile.uri)).then(_ => WiFiP2P.sendFiles(files));
    } else {
        return Promise.resolve();
    }
}

export const sendFilesToServer = (macAddr, files) => {

    console.log(files, macAddr);
    files.forEach(file => {
        WiFiP2P.connect(macAddr)
            // Resolve connection details using getConnectionInfo
            .then(() => WiFiP2P.getConnectionInfo())
            .then(() => {
                console.log('Sending Files');
                return sendFiles(files);
            })
            .catch(err => console.log('Error occurred', err));
    });
}

export const receiveFromClient = () => {

    console.log('Can receive now');

    // Receive file metadata using receiveMessage()
    WiFiP2P.removeGroup(() => console.log('Removed old group'))
        .then(() => {
            console.log('Successfully created group');
            return WiFiP2P.createGroup();
        })
        .then(() => {
            console.log('Waiting for message');
            return WiFiP2P.receiveMessage();
        })
        // .then(() => {
        //     return PermissionsAndroid.request(
        //         PermissionsAndroid.PERMISSIONS.WRITE_EXTERNAL_STORAGE,
        //         {
        //             'title': 'Access to write',
        //             'message': 'WRITE_EXTERNAL_STORAGE'
        //         }
        //     )
        // })

        // Receive file and store it based on the metadata
        .then(message => {
            console.log('Received message ', message);
            return WiFiP2P.receiveFile('/storage/emulated/0/Music/', message);
        })
        .catch(err => console.log(err));
}
kirillzyusko commented 4 years ago

Ooops, sorry, didn't notice it. Could you attach adb logcat output then?

kirillzyusko commented 4 years ago

But I can try to say in advance where is the problem :) You have %3A in you path .../msf%3A14. As I described in https://github.com/kirillzyusko/react-native-wifi-p2p/issues/26 such symbols should be properly encoded. In your case it should be .../msf:14. Not .../msf%3A14.

ghost commented 4 years ago

So how do I encode them? Do I parse through the string and modify it or is there any built in library that can be used for the same?

kirillzyusko commented 4 years ago

Try to use this package. Or try to search in google how to encode/decode URI. Maybe you could find better way :) I'm using encodeURI in browsers. Not sure whether this method is available in react-native.

But at the beginning you can "hardcode" this path. Just for checking whether my suggestion is working in your case or there are others problems as well. And if it works - try to find a long term solution :)

ghost commented 4 years ago

So, I did the decodeURI thing, as you will be able to see in the screenshot attached. Also, see what the output of getConnectionInfo() gives. So, clearly it is able to detect the group and attempt to connect to it. However, actually connecting is where the issue is happening (in the sendMessage() and sendFile() functions) Screenshot from 2020-08-23 02-47-44

kirillzyusko commented 4 years ago

Okay, then output from adb should help :)

ghost commented 4 years ago

output_adb.txt

Here it is

kirillzyusko commented 4 years ago

Did you miss a callback inside of promises chain? Instead of:

return WiFiP2P.sendMessage(nextFile.name).then(WiFiP2P.sendFile(nextFile.uri)).then(_ => WiFiP2P.sendFiles(files));

Shouldn't be:

return WiFiP2P.sendMessage(nextFile.name).then(() => WiFiP2P.sendFile(nextFile.uri)).then(_ => WiFiP2P.sendFiles(files)/*not sure, that method exist in my API :)*/);

?

ghost commented 4 years ago

Oops, I certainly missed the callback. Thanks for pointing that out. However, while correcting that mistake certainly helped remove the unnecessary error that was there because of the Promise chain, it still didn't resolve the ECONConnectionRefused thing. Here is how the thing looks after correcting for the callback and only that change. Also, thanks for pointing that out. It wasn't your function. Renamed it as well. However, the connection refused error persists

Also, find attached the ADB Logcat output

Screenshot from 2020-08-23 14-57-17

output_adb_new.txt

kirillzyusko commented 4 years ago

Now you are trying to send two files. It will not work. sendFile opens socket connection. And since you are trying send two files - second connection will be rejected because the port is already in usage. It's happening because you are sending files via forEach. And it sends files in parallel. But you should do it sequentially. Also connect and getConnectionInfo should be called not inside of for-loop. Try to send one file. I can assure, that it will work. Or try to send one message (without file). I also can assure that it will work perfectly.

ghost commented 4 years ago

The sendFiles method that I have created will do it sequentially (I forgot to remove the for loop earlier. Fixed that) by recursively calling the sendMessage and sendFile functions only after the previous succeed. In addition, I've tried sending only one file but the same issue persists

kirillzyusko commented 4 years ago

In addition, I've tried sending only one file but the same issue persists

Could you attach logs from this case? Also try to change your devices roles (if 1st device was responsible for sending and 2nd for receiving, try to send file from 2nd and receive on first. It may help. And keep things simple - try to send only messages. Without files.)

ghost commented 4 years ago

Tried both of your recommendations. Here is the attached log file. If you feel like, you may view my app code (I made the repo public)

Here it is : https://github.com/c-thun/meridio

You will see two send cases in the adb logcat. I am trying to only send the message this time (regardless of the console output) and the first time, I send the name of one file as a message only while the other time I send the name of two files

output_onceAgain.txt

And the logs attached below (output_twiceAgain.txt) is the logcat output when I just directly use sendMessage() as follows

 WiFiP2P.connect(macAddr)
        // Resolve connection details using getConnectionInfo
        .then(() => {
            console.log('Getting connection info');
            return WiFiP2P.getConnectionInfo().then(info => console.log('getConnectionInfo', info));
        })
        .then(() => {
            console.log('Sending Files');
            // return sendFiles(files);
            return WiFiP2P.sendMessage('Hey ya');
        })
        .catch(err => console.log('Error occurred', err));

And try to receive the message on the other device. I also tried this after reversing the roles to no avail

output_twiceAgain.txt

kirillzyusko commented 4 years ago

I will try to run your repo on my phones.

ghost commented 4 years ago

By some random method : One device did manage to send a Hey message to the other (I saw it received on the second device) but that so far has just been an anomaly. Unable to reproduce it

ghost commented 4 years ago

Any updates?

kirillzyusko commented 4 years ago

@c-thun Still haven't had a chance/free time to test it... Too busy with main work, unfortunately :(

ghost commented 4 years ago

No worries. With Nearby Share being pushed out to all android users, my project no longer is time constrained and has become more of a enthusiast learning endeavour. Take your time. I am also between projects currently :)

kirillzyusko commented 4 years ago

@c-thun By the way, did you consider to try to use nearby API?

ghost commented 4 years ago

I didn't know this API was there. This sounds perfect. I'll try this out asap. Thanks a lot