Obtaining data from my TP-Link router programmatically - android
I'm trying to design an app that can communicate with my router programmatically using the same endpoints as the web interface (there's a demo on TP-Link's website). My router is a TP-Link TD-W8980, if that matters.
The format appears to be very difficult to decipher. Here is a request which obtains the data for the status part of my app. This can obtain a valid response from the router but I'm not sure why!
I'm especially confused by the #0,0,0,0,0,0#0,0,0,0,0,0] part of the response. It's the only part I haven't managed to work out but I think I recall reading it's to do with the stack?!?
[SYS_MODE#0,0,0,0,0,0#0,0,0,0,0,0]0,1
mode
[LAN_HOST_CFG#1,0,0,0,0,0#0,0,0,0,0,0]1,1
DNSServers
[WAN_DSL_INTF_CFG#1,0,0,0,0,0#0,0,0,0,0,0]2,8
upstreamCurrRate
downstreamCurrRate
upstreamMaxRate
downstreamMaxRate
upstreamNoiseMargin
downstreamNoiseMargin
upstreamAttenuation
downstreamAttenuation
[IGD_DEV_INFO#0,0,0,0,0,0#0,0,0,0,0,0]3,3
softwareVersion
hardwareVersion
upTime
[LAN_IP_INTF#0,0,0,0,0,0#0,0,0,0,0,0]4,2
IPInterfaceIPAddress
X_TPLINK_MACAddress
[LAN_HOST_ENTRY#0,0,0,0,0,0#0,0,0,0,0,0]5,4
leaseTimeRemaining
MACAddress
hostName
IPAddress
[WAN_PPP_CONN#0,0,0,0,0,0#0,0,0,0,0,0]6,4
enable
connectionStatus
externalIPAddress
DNSServers
If it helps, the names in capitals (e.g. SYS_MODE) is the name of the section. The number after the ] is a counter stating the section number (sections can be in any order). The final number following the , is the number of parameters that follow in this section.
There are also request types for each section. In the example above, the URL is http://192.168.1.1/cgi?1&1&1&1&5&5&5. As you can see the two main request types are 1 and 5.
Here is an example response from the server. As you can see, some of the sections can be returned more than once, which makes the first number of the six zeros increment each time.
[0,0,0,0,0,0]0
mode=DSL
[1,0,0,0,0,0]1
DNSServers=x.x.x.x,x.x.x.x
[1,0,0,0,0,0]2
upstreamCurrRate=928
downstreamCurrRate=3072
upstreamMaxRate=1068
downstreamMaxRate=3104
upstreamNoiseMargin=60
downstreamNoiseMargin=57
upstreamAttenuation=295
downstreamAttenuation=546
[0,0,0,0,0,0]3
softwareVersion=0.6.0 1.3 v000e.0 Build 131012 Rel.51720n
hardwareVersion=TD-W8980 v1 00000000
upTime=x
[1,1,0,0,0,0]4
IPInterfaceIPAddress=192.168.1.1
X_TPLINK_MACAddress=xx:xx:xx:xx:xx:xx
[1,0,0,0,0,0]5
leaseTimeRemaining=-1
MACAddress=xx:xx:xx:xx:xx:xx
hostName=X
IPAddress=192.168.1.2
[2,0,0,0,0,0]5
leaseTimeRemaining=-1
MACAddress=xx:xx:xx:xx:xx:xx
hostName=X
IPAddress=192.168.1.4
[3,0,0,0,0,0]5
leaseTimeRemaining=-1
MACAddress=xx:xx:xx:xx:xx:xx
hostName=X
IPAddress=192.168.1.11
[4,0,0,0,0,0]5
leaseTimeRemaining=-1
MACAddress=xx:xx:xx:xx:xx:xx
hostName=X
IPAddress=192.168.1.5
[1,2,1,0,0,0]6
enable=1
connectionStatus=Connected
externalIPAddress=x.x.x.x
DNSServers=x.x.x.x,x.x.x.x
[2,1,1,0,0,0]6
enable=0
connectionStatus=Unconfigured
externalIPAddress=0.0.0.0
DNSServers=0.0.0.0,0.0.0.0
[3,1,1,0,0,0]6
enable=0
connectionStatus=Unconfigured
externalIPAddress=0.0.0.0
DNSServers=0.0.0.0,0.0.0.0
[error]0
I would appreciate any explanation of this format and if it appears anywhere else on the web. I've never seen such a system before!
Related
How to Ebay oauth process for Android?
I have managed to achieve HTTP requests with Volley to an API without auth, but with Ebay API things are becoming harder. https://github.com/eBay/ebay-oauth-android-client The above link has the an example, yet it is not filled with a real case scenario. ApiSessionConfiguration.initialize ( apiEnvironment = ApiEnvironment.PRODUCTION, apiConfiguration = ApiConfiguration( "<Client ID>", "<Redirect Uri>", "<space separated scopes>" ) ) Client ID appears on Ebay Developer Account as is and i guess "XXXX-XXXX-PRD-XXXX-XXXX" something on that lines is correct. Redirect Uri on the other hand seems more confusing. Which string needs to be placed there? The "RuName" that is similar to the Client ID XXXX-XXXX-XXXX-XXXX? Or something like "http://..."? Space separated scopes hopefully are; "https://api.ebay.com/oauth/api_scope/sell.marketing.readonly" + " " + "https://api.ebay.com/oauth/api_scope/sell.marketing" ... and so on. I have further doubts about the part that requires having a second activity to be overriden on the manifest but i guess that will be better asked separatedly.
Nest ETA update not working: No write permission(s) for field(s): eta
I'm building an Application that integrates with your Nest devices (both the thermostat and the Nest Protect, but this issue is about the thermostat). What I'm trying to do is set my thermostat's ETA to be in x minutes (2 hours for example so 120 minutes). This is my code that I'm executing: SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSSZ"); final String path = buildStructureFieldPath(structureID, Keys.STRUCTURE.ETA); Structure.ETA eta = new Structure.ETA.Builder() .setTripID(tripId) .setEstimatedArrivalWindowBegin(sdf.format(estimatedArrivalBegin)) .setEstimatedArrivalWindowEnd(sdf.format(estimatedArrivalEnd)) .build(); sendRequest(path, eta.toJSON().toString(), listener); The path is /structures/MY_STRUCTURE_ID/eta Unfortunately that's not working. I'm always getting an error code -2 and error message: No write permission(s) for field(s): eta And that's were it gets strange. No permission, but I did request the permission and I did an authenticate, which is successful, before launching the update call. In the two attached screenshots you can see first my Nest Developer Account where you can find the ETA write permission and in the second you can see the logging from within my app (using the NestAPI as can be found on GitHub, just added the ETA feature myself). Anyone have any idea on how to solve this issue?
Can you print out the exact JSON blob you're sending and post it here? (the value of eta.toJSON().toString()) Best guess is that it isn't formatted exactly correctly and as such is maybe attempting to write in such a way that doesn't adhere to the api-reference. This is the format that it needs to match: "eta": { "trip_id": "myTripHome1024" , "estimated_arrival_window_begin": "2015-10-31T22:42:59.000Z" , "estimated_arrival_window_end": "2015-10-31T23:59:59.000Z" } Single line: {"eta":{"trip_id":"myTripHome1024","estimated_arrival_window_begin":"2015-10-31T22:42:59.000Z","estimated_arrival_window_end": "2015-10-31T23:59:59.000Z"}} To pinpoint exactly which field may be erroneous, try sending just one change at a time for each ie: structures/ID/eta/trip_id, etc for the others. Useful JSON Validator: http://jsonlint.com/ You could also try to send it to /structures/MY_STRUCTURE_ID.json?auth=[TOKEN] instead of /structures/MY_STRUCTURE_ID/eta.
Android Jwebsocket custom protocol
I am opening a connection setting up a custom protocol like this: WebSocketSubProtocol d = new WebSocketSubProtocol("MyCustomProto",WebSocketEncoding.TEXT); mJWC.addSubProtocol(d); mJWC.open(mURL); But... Server side, I receive tis in the protocol string "org.jwebsocket.json MyCustomProto" How can I remove from the string the "org.jwebsocket.json" ? I don't wanna do it server side... Thanks!
I will answer to my own question. By calling the "addSubProtocol" doesn't seem to be the right solution for couple of reasons: if you call those 3 lines of code multiple time (if the first time the connection failed for example..) well the the protocol string would be something like "org.jwebsocket.json MyCustomProto MyCustomProto" It just keep adding the protocol.. So I found a turn around. Now I don't use that "addSubProtocol" but instead I defined the protocol directly when I create the socket mJWC = new BaseTokenClient("client||"+code+"||"+name,WebSocketEncoding.TEXT); Voila.. Now no more "org.jwebsocket.json" anymore
Android SSLEngine example
I need to work with a TCP socket over TLS for an app I'm working on. I've been through dozens of examples and while I have no problem getting through the handshake, I can't seem to read the input stream through any means (tried a lot, including readline(), reading to character array, etc). every time I try, the app freezes on that spot. If I debug, it never goes to the next line of code. In an attempted solution, I decided to move over to using an SSLEngine, since that's supposed to be the Java 1.5 answer to java.nio for SSL. However, I have found one example (here: http://docs.oracle.com/javase/7/docs/technotes/guides/security/jsse/samples/sslengine/SSLEngineSimpleDemo.java) which is more than a little confusing to me, and I've not been successful implementing it. When I try, the unwrap() call yields an empty buffer, where I know (from using OpenSSL on the command line) that the service in question pushes data back down the pipe. Suggestions are welcome, I've burned way too much time on this already. Here's the relevant code: SSLEngine engine = sslContext.createSSLEngine(uri.getHost(), uri.getPort()); engine.setUseClientMode(true); engine.beginHandshake(); SSLSession session = engine.getSession(); int bufferMax = session.getPacketBufferSize(); int appBufferMax = session.getApplicationBufferSize() + 50; ByteBuffer cTo = ByteBuffer.allocateDirect(bufferMax); ByteBuffer sTo = ByteBuffer.allocateDirect(bufferMax); ByteBuffer out = ByteBuffer.wrap(sessionId.getBytes()); ByteBuffer in = ByteBuffer.allocate(appBufferMax); debug("sending secret"); SSLEngineResult rslt = engine.wrap(out, cTo); debug("first result: " + rslt.toString()); sTo.flip(); rslt = engine.unwrap(sTo, in); debug("next result" + rslt.toString());
This implementation is missing some key pieces. Namely the handshake can bounce between several states NEED_WRAP, NEED_UNWRAP, NEED_TASK to negotiate a connection. This means you cannot just call one and then the other. You will need to loop over the states until a handshake has completed. while (handshaking) { switch (state) { case NEED_WRAP: doWrap(); break; case NEED_UNWRAP: doUnwrap(); break; case NEED_TASK: doTask(); break; } } A full working example of Java SSL and NIO Now that said, you should be aware the SSLEngine on Android is broken. Google recommends using threads and blocking sockets according to that thread.
I have written something to make using SSLEngine easier. It can be used with NIO or for other use cases. Available here SSLFacade
unwrap() can yield an empty buffer if what was unwrapped was an SSL handshake message or alert, rather than application data. There's not enough information here to say more. What was the engine status afterwards?
beginHandshake does not proceed the handshake, it is just used to inform the SSLEngine that you want to perform the handshake for the next calls to wrap/unwrap. It's useful when you want to do another handshake. For the initial one, it is not needed as the first call to wrap will initiate the handshake. Besides, you have to check the result of the wrap and unwrap methods to know if all the data has been correctly encoded. It can happen that you have to call the methods several times to process all the data. The following link might help: http://onjava.com/onjava/2004/11/03/ssl-nio.html Or this question: SSL Handshaking Using Self-Signed Certs and SSLEngine (JSSE)
Android URLConnection class cannot get content lenght using 3G internet connection
I've got the following piece of code: URL url = new URL("http://myserver.com/getFile.php"); URLConnection conexion = url.openConnection(); conexion.connect(); int lenghtOfFile = conexion.getContentLength(); Everything works fine until I work with WiFi connection. If I try to run this code when there is only GPRS/3G connection available, conexion.getContentLength() returns -1. Any idea why? EDIT: I've check the headers using getHeaderFields(). They are different if I use 3G network. Basically there is no Content-Length in this case. Any idea why server returns different headers? I'm not using any special script to provide the file, I only get the file that is placed at given location. Entire header for the WiFi case: {Accept-Ranges=[bytes], Connection=[Keep-Alive], Content-Length=[628254], Content-Type=[text/plain; charset=UTF-8], Date=[Tue, 29 Nov 2011 11:22:50 GMT], ETag=["7a0c7-9961e-4af3f38778500"], Keep-Alive=[timeout=15], Last-Modified=[Fri, 14 Oct 2011 09:52:52 GMT], Server=[Apache/2.2.9 (Debian) PHP/5.2.6-1+lenny9 with Suhosin-Patch mod_python/3.3.1 Python/2.6.6 mod_ssl/2.2.9 OpenSSL/0.9.8o mod_wsgi/3.3 mod_perl/2.0.4 Perl/v5.10.0]} Entire header for the case when using 3G: {Accept-Ranges=[bytes], Connection=[Keep-Alive], Content-Type=[text/plain; charset=UTF-8], Date=[Tue, 29 Nov 2011 11:20:33 GMT], ETag=["7a0c7-9961e-4af3f38778500"], Keep-Alive=[timeout=15], Last-Modified=[Fri, 14 Oct 2011 09:52:52 GMT], Server=[Apache/2.2.9 (Debian) PHP/5.2.6-1+lenny9 with Suhosin-Patch mod_python/3.3.1 Python/2.6.6 mod_ssl/2.2.9 OpenSSL/0.9.8o mod_wsgi/3.3 mod_perl/2.0.4 Perl/v5.10.0], Transfer-Encoding=[chunked], Warning=[214 warkaz-fe07 "Transformation applied"]}
Are you sure that the server provides the content length by sending the Content-Length header in the response? From the headers it's clear that your provider has some kind of proxy in place that does a transformation, stripping the content-length in the process. The warning header clearly indicates this. You could try returning a different type of content type (you are now getting text/plain), maybe this particular proxy won't touch it. It's not a great solution of course, there are a lot things carriers may have to "optimize" their network in some way. You could also try a HEAD request using a range header to get a ballpark of the content size. In that case you'd guess a few ranges, like 100k, 1000k etc to see if the server thinks that's an acceptable range. You could use that fake range for your progress. Again, this isn't a very good solution but if you really need the progress, it's something to try. In the end it's best to just show the progress as unknown if there's no length known.
Since you are using new URL("http://myserver.com/getFile.php"); I suppose you are using a personal server that you have set up, and when using WiFi your phone is in your local network and thereby can see your server, but when you are trying to connect via GPRs/3G you are trying to access your local server from the internet.
It is probably due to a limitation from your carrier. Try to avoid needing this value. (for example, by reading the inputStream until you cannot read it).