tdlib / td

Cross-platform library for building Telegram clients
https://core.telegram.org/tdlib
Boost Software License 1.0
7.16k stars 1.45k forks source link

Connectivity issue on watchOS #1442

Closed kkmoskalenko closed 3 years ago

kkmoskalenko commented 3 years ago

I am creating a standalone Telegram client for Apple Watch that depends on TDLib. I managed to build the library for watchOS 6 (both for real Apple Watch devices – armv7k, arm64_32, and for simulators – i386, x86_64), however, I noticed strange behavior regarding network connectivity. The point is that the library works as expected on a watchOS Simulator, but fails to connect to Telegram servers when running on a physical device.

I am attaching TDLib logs generated by both the simulator and the real device running the same app (my code is almost identical to the Swift example). I think the main error is PosixError : No route to host and it is present on multiple log lines:

[1;33m[ 2][t 4][1615700144.824725151][ConnectionCreator.cpp:897][#1][!ConnectionCreator] [149.154.175.50:443] to DcId{1}: [PosixError : No route to host : 65 : Failed to connect to [149.154.175.50:443]][0m
[1;33m[ 2][t 4][1615700145.084172248][ConnectionCreator.cpp:897][#1][!ConnectionCreator] [149.154.175.50:80] to DcId{1}: [PosixError : No route to host : 65 : Failed to connect to [149.154.175.50:80]][0m
[1;33m[ 2][t 4][1615700145.805907964][ConnectionCreator.cpp:897][#1][!ConnectionCreator] [149.154.175.50:5222] to DcId{1}: [PosixError : No route to host : 65 : Failed to connect to [149.154.175.50:5222]][0m
[1;33m[ 2][t 4][1615700146.088163137][ConnectionCreator.cpp:897][#1][!ConnectionCreator] [[2001:b28:f23d:f001::a]:443] to DcId{1}: [PosixError : No route to host : 65 : Failed to connect to [[2001:b28:f23d:f001::a]:443]][0m
[1;33m[ 2][t 4][1615700148.080904006][ConnectionCreator.cpp:897][#1][!ConnectionCreator] [[2001:b28:f23d:f001::a]:80] to DcId{1}: [PosixError : No route to host : 65 : Failed to connect to [[2001:b28:f23d:f001::a]:80]][0m
[1;36m[ 3][t 4][1615700149.878611087][ConfigManager.cpp:664][#1][!Recoverer][&config_recoverer] Get SimpleConfig error [PosixError : No route to host : 65 : Failed to connect to [8.8.8.8:443]][0m

I am trying to figure out if this issue is related to TDLib itself or am I running into some hardware limitations of the Apple Watch? I have also found a few mentions (Apple Developer Forums and Medium article) that basically say the following:

watchOS apps are not allowed to use low-level networking except in very limited circumstances, namely, audio streaming apps

If so, is it even possible to properly run TDLib on an Apple Watch device at all? If not, what are the options? MTProto custom client only?

levlam commented 3 years ago

You investigated the issue correctly. Apps are forced to use watchOS-specific API to access network on physical devices. We weren't aware of this restriction, so TDLib isn't able to use network on watchOS now. To fix this, you need to rewrite network implementation for watchOS, namely rewrite implementation of the class SocketFd in Swift using Apple-provided API. Some related classes also needs to be rewrited. This is a task of medium-hard difficulty, but it is much simpler than writing an MTProto implementation from scratch. From the other side, starting from Telegram iOS MTProto implementation in Swift should be of the same difficulty or even simpler.

NikitaSarin commented 3 years ago

The unpleasant point is that using sockets on watchOS is only possible for streaming audio. https://developer.apple.com/forums/thread/19399

Also access to the low-level network, as well as the implementation of the URLProtocol is denied. https://developer.apple.com/documentation/foundation/urlprotocol

It turns out that instead of a socket, we need to use http long polling? And it is still unclear for me how to implement MTProto for URLSession without URLProtocol implementation. This seems like a pretty complicated task.

arseny30 commented 3 years ago

It is also possible to use mtproto over http. It is kind of supported but turned off. https://github.com/tdlib/td/blob/master/td/mtproto/HttpTransport.cpp Sadly, one still need to somehow connect it with Apple's API.

NikitaSarin commented 3 years ago

I forced use of http, but it had no effect. Probably, this really needs to be done over http but using native URLSession.

mib32 commented 3 years ago

Consider using TaaS serverless TDLib solution - you could use TDLib from watchOS by simply sending HTTP requests to taas server.

kkmoskalenko commented 3 years ago

It is also possible to use mtproto over http. It is kind of supported but turned off. https://github.com/tdlib/td/blob/master/td/mtproto/HttpTransport.cpp Sadly, one still need to somehow connect it with Apple's API.

As far as I am concerned, this will not work either, because the ConnectionCreator::find_connection method will still open a TCP socket (even in "over HTTP" mode): https://github.com/tdlib/td/blob/449c37c41f36260b8c12f223d75c434c524061d6/td/telegram/net/ConnectionCreator.cpp#L728

And working with sockets on Apple Watch is not allowed, except for audio streaming :(

levlam commented 3 years ago

@kkmoskalenko

As far as I am concerned, this will not work either

"Sadly, one still need to somehow connect it with Apple's API."

kkmoskalenko commented 3 years ago

@levlam, I mean sockets are not allowed even through Apple's API

https://developer.apple.com/forums/thread/127232

Prior to watchOS 6 there was no support for low-level networking APIs in watchOS. watchOS 6 does support the use of Network framework, but only in the context of an audio streaming session. Low level networking APIs such at Network framework, BSD Sockets, and socket streams that are used outside the context of an audio stream session on watchOS will not work as expected and may result in inconsistent behavior compared to iOS. If you are not working on an audio app and wanting to utilize Network framework it’s best to do this work on iOS.

levlam commented 3 years ago

@kkmoskalenko And the phrase about connection with Apple's API was exactly about this.

levlam commented 3 years ago

Built-in support for watchOS networking APIs was added to TDLib, so now there should be no problems with using TDLib on real device if TDLib is built as shown in https://github.com/tdlib/td/tree/master/example/ios.