chrome sockets sometimes can't bind to a port, even after reloading the packaged app

1,400 views
Skip to first unread message

James Mortensen

unread,
Jun 4, 2013, 8:52:35 PM6/4/13
to chromi...@chromium.org
I've built a Chrome App that uses a TCP socket listener to receive data from another application.  I'm binding to 127.0.0.1:48000.  In some cases, when I reload the app from Tools->Extensions, it seems that the application is unable to bind to port 48000.  When running Chrome in the debug mode, I see the following in the chrome_debug.log:

52168:39683:0604/170056:ERROR:tcp_server_socket_libevent.cc(84)] bind() returned an error: Address already in use


Since the app was reloaded, there shouldn't be a problem binding to the port, in theory.  Ideally, I'd like to be able to force the app to bind to a port, but I'm not a networking expert and don't know if this is possible.  I did run netstat to see if something is binding to the port, and this is what I see:

bash-3.2# netstat -anp tcp|grep 48000
tcp4       0      0  127.0.0.1.65392        127.0.0.1.48000        SYN_SENT   
tcp4     359      0  127.0.0.1.48000        127.0.0.1.62389        CLOSE_WAIT 
tcp4     359      0  127.0.0.1.48000        127.0.0.1.62379        CLOSE_WAIT 
tcp4     359      0  127.0.0.1.48000        127.0.0.1.62346        CLOSE_WAIT 
tcp4     359      0  127.0.0.1.48000        127.0.0.1.62326        CLOSE_WAIT 
tcp4     359      0  127.0.0.1.48000        127.0.0.1.62322        CLOSE_WAIT 
tcp4     359      0  127.0.0.1.48000        127.0.0.1.62313        CLOSE_WAIT 
tcp4     359      0  127.0.0.1.48000        127.0.0.1.62300        CLOSE_WAIT 
tcp4     359      0  127.0.0.1.48000        127.0.0.1.62279        CLOSE_WAIT 
tcp4     359      0  127.0.0.1.48000        127.0.0.1.62276        CLOSE_WAIT 
tcp4     359      0  127.0.0.1.48000        127.0.0.1.62270        CLOSE_WAIT 
tcp4     359      0  127.0.0.1.48000        127.0.0.1.62268        CLOSE_WAIT 
tcp4     359      0  127.0.0.1.48000        127.0.0.1.62265        CLOSE_WAIT 
tcp4     359      0  127.0.0.1.48000        127.0.0.1.62262        CLOSE_WAIT 
tcp4     359      0  127.0.0.1.48000        127.0.0.1.62257        CLOSE_WAIT 
tcp4     359      0  127.0.0.1.48000        127.0.0.1.62248        CLOSE_WAIT 
tcp4     359      0  127.0.0.1.48000        127.0.0.1.62246        CLOSE_WAIT 
tcp4     359      0  127.0.0.1.48000        127.0.0.1.62244        CLOSE_WAIT 
tcp4     359      0  127.0.0.1.48000        127.0.0.1.62242        CLOSE_WAIT 
tcp4     359      0  127.0.0.1.48000        127.0.0.1.62240        CLOSE_WAIT 
tcp4     359      0  127.0.0.1.48000        127.0.0.1.62201        CLOSE_WAIT 
tcp4       0      0  127.0.0.1.48000        *.*                    LISTEN     


If it helps, one thing that I did to try and test this is reload the app over and over again very quickly, as I'm trying to find ways to detect a problem with the port and adjust, either by picking a different port or by forcing the port to bind, but I also want to be sure this isn't a bug that should be reported.

If this is a bug, please let me know what other information that I can put together in order to replicate this issue.  If it's not a bug, then I'll just pick a different port and implement a discovery mechanism in both apps so they can establish connectivity by selecting a range of ports.  I'd like to avoid this, if possible, as it will add some complexity that could possibly be handled lower in the stack.

Thank you!

James

Hoa V. Dinh

unread,
Jun 4, 2013, 9:00:59 PM6/4/13
to James Mortensen, chromi...@chromium.org
Is there a way to use some equivalent of (C socket API) setsockopt() with the option SO_REUSEADDR to avoid that kind of issue in chrome socket API?

I'm wondering what we can pass as options to the following call:
chrome.socket.create(SocketType type, object options, function callback)
It's not clear in the documentation.

-- 
Hoa V. Dinh

--
You received this message because you are subscribed to the Google Groups "Chromium Apps" group.
To unsubscribe from this group and stop receiving emails from it, send an email to chromium-app...@chromium.org.
To post to this group, send email to chromi...@chromium.org.
Visit this group at http://groups.google.com/a/chromium.org/group/chromium-apps/?hl=en.
For more options, visit https://groups.google.com/a/chromium.org/groups/opt_out.
 
 

Ken Rockot

unread,
Jun 4, 2013, 9:33:52 PM6/4/13
to Hoa V. Dinh, James Mortensen, chromi...@chromium.org
Can you modify so that it waits some time before trying to bind a port, and then provide netstat output from the period of time between hitting reload and having the app attempt to bind? (specifically for a case in which binding then goes on to fail).

Also it looks like the clients aren't properly closing their end of the connection (hence all the CLOSE_WAIT states).

Ken Rockot

unread,
Jun 4, 2013, 10:11:18 PM6/4/13
to Hoa V. Dinh, James Mortensen, chromi...@chromium.org
It's most likely that you have a server socket hanging around in TIME_WAIT and Hoa's suggestion is correct, albeit unsupported by the API. In the unlikely event that you don't observe a TIME_WAIT state between reload and listen, this could be a deeper issue.

In any case I've filed http://crbug.com/246867 because I think this is a good feature to have.

Bei Zhang

unread,
Jun 5, 2013, 1:54:29 PM6/5/13
to chromi...@chromium.org, Hoa V. Dinh, James Mortensen
This is not because of TIME_WAIT. The port is in LISTEN state.

I suspect that the previous socket is not closed upon reload. It looks more likely to be a memory leak to me.

James: are you sure you are reloading the app using extensions page or chrome.runtime.reload()? Reload the inspector of background page do creates memory leak currently. 

roc...@chromium.org

unread,
Jun 5, 2013, 2:01:45 PM6/5/13
to chromi...@chromium.org, Hoa V. Dinh, James Mortensen
It's wasn't clear to me if that netstat output was from when the app was running or not running. I was assuming it was while running, hence the LISTEN state. If not, that's clearly a problem.

James, could you clarify this as well?

James Mortensen

unread,
Jun 6, 2013, 1:46:39 PM6/6/13
to chromi...@chromium.org, Hoa V. Dinh, James Mortensen
I'm reloading from the RELOAD link in Tools -> Extensions.  The netstat was taken while the app was running after not being able to successfully bind the port.  Killing chrome and restarting it of course released the port.

It is possible I'm doing something wrong as networking isn't something I consider myself an expert at.  I've tried killing the socket using socket.destroy:

    socket.destroy(socketInfo.socketId);

This is what I'm trying to do to stop the listener, but that's not enough.  I like the idea of being able to pass something into the API like SO_REUSEADDR.   

Let me know if there's any other information I can provide to be helpful! :)

Thank you!
James

James Mortensen

unread,
Jun 6, 2013, 5:02:15 PM6/6/13
to chromi...@chromium.org, Hoa V. Dinh, James Mortensen
Here's some more information that may prove helpful:

  • I installed two copies of my app, one in one profile and one in another profile.
  • Both profiles try to bind to the same port.  
  • By reloading each app independent of the other, one is able to steal the port from the other app, but eventually they both lose the ability to bind to the port.
  • Even if I maintain an array of all of my socketId's and try to loop through all of them calling socket.disconnect and socket.destroy, they're still unable to bind to the port.
Here's the netstat output with both apps running and both of them now unable to bind to the port:

bash-3.2# netstat -anp tcp|grep 48000
tcp4     357      0  127.0.0.1.48000        127.0.0.1.62772        ESTABLISHED
tcp4       0      0  127.0.0.1.62772        127.0.0.1.48000        ESTABLISHED
tcp4     357      0  127.0.0.1.48000        127.0.0.1.62770        ESTABLISHED
tcp4       0      0  127.0.0.1.62770        127.0.0.1.48000        ESTABLISHED
tcp4     357      0  127.0.0.1.48000        127.0.0.1.62768        ESTABLISHED
tcp4       0      0  127.0.0.1.62768        127.0.0.1.48000        ESTABLISHED
tcp4     357      0  127.0.0.1.48000        127.0.0.1.62766        ESTABLISHED
tcp4       0      0  127.0.0.1.62766        127.0.0.1.48000        ESTABLISHED
tcp4     357      0  127.0.0.1.48000        127.0.0.1.62756        ESTABLISHED
tcp4       0      0  127.0.0.1.62756        127.0.0.1.48000        ESTABLISHED
tcp4     357      0  127.0.0.1.48000        127.0.0.1.62754        ESTABLISHED
tcp4       0      0  127.0.0.1.62754        127.0.0.1.48000        ESTABLISHED
tcp4     357      0  127.0.0.1.48000        127.0.0.1.62751        CLOSE_WAIT 
tcp4     357      0  127.0.0.1.48000        127.0.0.1.62748        CLOSE_WAIT 
tcp4     357      0  127.0.0.1.48000        127.0.0.1.62746        CLOSE_WAIT 
tcp4     357      0  127.0.0.1.48000        127.0.0.1.62744        CLOSE_WAIT 
tcp4       0      0  127.0.0.1.48000        *.*                    LISTEN     
bash-3.2# 


Now, I'm shutting down one of the apps to see if that helps release the port............

It doesn't... the remaining app is unable to bind to the port, and here is the netstat output:

bash-3.2# netstat -anp tcp|grep 48000
tcp4     357      0  127.0.0.1.48000        127.0.0.1.63015        ESTABLISHED
tcp4       0      0  127.0.0.1.63015        127.0.0.1.48000        ESTABLISHED
tcp4     357      0  127.0.0.1.48000        127.0.0.1.63012        ESTABLISHED
tcp4       0      0  127.0.0.1.63012        127.0.0.1.48000        ESTABLISHED
tcp4     370      0  127.0.0.1.48000        127.0.0.1.63009        CLOSE_WAIT 
tcp4     357      0  127.0.0.1.48000        127.0.0.1.63008        ESTABLISHED
tcp4       0      0  127.0.0.1.63008        127.0.0.1.48000        ESTABLISHED
tcp4     357      0  127.0.0.1.48000        127.0.0.1.63006        ESTABLISHED
tcp4       0      0  127.0.0.1.63006        127.0.0.1.48000        ESTABLISHED
tcp4     357      0  127.0.0.1.48000        127.0.0.1.63001        ESTABLISHED
tcp4       0      0  127.0.0.1.63001        127.0.0.1.48000        ESTABLISHED
tcp4       0      0  127.0.0.1.48000        127.0.0.1.62999        CLOSE_WAIT 
tcp4     370      0  127.0.0.1.48000        127.0.0.1.62998        CLOSE_WAIT 
tcp4     357      0  127.0.0.1.48000        127.0.0.1.62996        ESTABLISHED
tcp4       0      0  127.0.0.1.62996        127.0.0.1.48000        ESTABLISHED
tcp4       0      0  127.0.0.1.48000        *.*                    LISTEN     


Now, I'll try reloading the app to see if that helps..............

Reloading the app using chrome.runtime.reload() now allows the app to bind to the port again, and here is the netstat output:

bash-3.2# netstat -anp tcp|grep 48000
tcp4       0      0  127.0.0.1.48000        *.*                    LISTEN     
bash-3.2# 


A temporary hack until this is resolved is for me to maintain state in my app in chrome storage, and if the port becomes unavailable for whatever reason, I can save state, reload, and then revert back to the state the app was in prior to the reload.  I also plan to use a port scanning technique where I simply use another port if the default is unavailable.

Neither of these are great solutions, of course.

Hope this helps!
James

James Mortensen

unread,
Nov 15, 2013, 2:28:48 AM11/15/13
to chromi...@chromium.org, Hoa V. Dinh, James Mortensen
Hello,

I wanted to follow up on this issue.  We stopped using TCP sockets altogether and abandoned the component of our app that required this.  My opinion and experience on the chrome.socket API is that it's just plain not production ready.  It's a nice concept, but until the app can release ports and re-bind to them without forcing users to completely shutdown and restart the app, this isn't something we can rely on.

We went through the same thing with XULRunner and their TCP sockets.  They'd just stop listening and require a complete restart of the app.  Mozilla, to the best of my knowledge, has never figured this out, which makes me think it just might not be possible for a browser to be able to release ports it was using that just got stuck.

This isn't intended to be negative but to just let you know where we're at with this particular feature.  Once it works and is more reliable, we would love to give it another try, as it has a lot of potential uses!

Hope this helps!

James

rpa...@chromium.org

unread,
Nov 15, 2013, 4:18:37 PM11/15/13
to chromi...@chromium.org, Hoa V. Dinh, James Mortensen
Hi James,

We have been working on a new socket API. One of the goals was to address issues with lifetime of sockets. I would be interested to understand exactly the issue(s) you were running into, so that we can make sure they are addressed in the new API.

Here are the 3 IDL files for the new API (we split the API in udp, tcp and tcp server):


AFAIK, these APIs are available in Canary/Dev channels (http://www.chromium.org/getting-involved/dev-channel).

We still have not implement support for SO_REUSEADDR, but it is no clear to me it would have helped in your scenario, since SO_REUSEADDR seems to work only if the port is in the TIME_WAIT state (i.e. not in the LISTENING state).

A few notes from the thread about the expected behavior of the existing (and new) socket API -- if you observe a different behavior, it is (most) likely a bug:

Please feel free to give us feedback and let us know if you are still seeing issues with the new (or old) API.

Thanks,
Renaud

James Mortensen

unread,
Nov 15, 2013, 7:11:52 PM11/15/13
to chromi...@chromium.org, Hoa V. Dinh, James Mortensen
Hello!

This actually sounds great!  We don't plan to run two apps parallel, but we do know sometimes networks issues happen, and being able to have the app recover it's connectivity will make our app appear a lot more robust.

In regards to the NEW API, what about cases where apps crash?  Will the platform be able to release the ports in those cases?  If not, what about the possibility of implementing a port range?  (For instance, if port 48000 is somehow blocked, automatically try port 48100 as defined in the manifest or in the Chrome API's themselves)?

I'l really glad to hear you're working on this stuff. I think it's important, and I wanted to show that we're still out here even if we aren't using it in our production app at the moment.

One thing we'd use this for is to build a separate, native Objective C based app to play a sound through the speakers when a call comes in while still piping the actual voice media through the headset.  Using TCP, our Chrome App can tell the Objective C app to "ring".  The Objective C app also places a tray app icon in the Mac OS system tray that, when clicked, sends a TCP request to the app to pull up the call screen.  This is just one of many use-cases.  


Hope this helps!
James

rpa...@chromium.org

unread,
Nov 22, 2013, 6:17:19 PM11/22/13
to chromi...@chromium.org, Hoa V. Dinh, James Mortensen


In regards to the NEW API, what about cases where apps crash?  Will the platform be able to release the ports in those cases?

Yes. (unless there is a bug in the platform, which we would surely fix).
 
If not, what about the possibility of implementing a port range?  (For instance, if port 48000 is somehow blocked, automatically try port 48100 as defined in the manifest or in the Chrome API's themselves)?

The platform currently doesn't offer a port range api, but afaik, there is nothing "smart" the platform could do an app could not do, i.e. the platform code would most likely be something alone the lines of "for each(port in range) { success = try_bind(port); if (success) break; }"
 

I'l really glad to hear you're working on this stuff. I think it's important, and I wanted to show that we're still out here even if we aren't using it in our production app at the moment.

Note that there is an open-source app (CIRC: https://chrome.google.com/webstore/detail/circ/bebigdkelppomhhjaaianniiifjbgocn?hl=en-US) using chrome.socket. Maybe you can take a look at the various technique the app uses to handle client and server socket connections.
 

One thing we'd use this for is to build a separate, native Objective C based app to play a sound through the speakers when a call comes in while still piping the actual voice media through the headset.  Using TCP, our Chrome App can tell the Objective C app to "ring".  The Objective C app also places a tray app icon in the Mac OS system tray that, when clicked, sends a TCP request to the app to pull up the call screen.  This is just one of many use-cases.  

Yes, this use-case should be supported.

David Brodbeck

unread,
Jan 31, 2014, 12:41:28 PM1/31/14
to rpa...@chromium.org, Chromium Apps, Hoa V. Dinh
Hi, I'm curious what the status of this new API is.  chrome.sockets doesn't seem to be defined in the current Canary build; is this still in progress or has the new API been abandoned?





--
GPG Key Fingerprint: 0DB7 4B50 8910 DBC5 B510 79C4 3970 2BC3 2078 D875

rpa...@chromium.org

unread,
Jan 31, 2014, 7:04:31 PM1/31/14
to chromi...@chromium.org, rpa...@chromium.org, Hoa V. Dinh
The new chrome.sockets.udp, chrome.sockets.tcp and chrome.sockets.tcpServer API(s) are available in M33.

David Brodbeck

unread,
Jan 31, 2014, 7:11:58 PM1/31/14
to rpa...@chromium.org, Chromium Apps, Hoa V. Dinh
Is there a new manifest permission to enable them, or something else I need to do to make them visible?  This is from the console of an app with {"socket": [ "tcp-connect:*:*" ]} permission:

> navigator.appVersion
"5.0 (Macintosh; Intel Mac OS X 10_9_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/34.0.1815.2 Safari/537.36"

> chrome.socket
Object {create: function, destroy: function, connect: function, bind: function, disconnect: function…}

> chrome.sockets.tcp
TypeError: Cannot read property 'tcp' of undefined

rpa...@chromium.org

unread,
Feb 1, 2014, 2:27:59 AM2/1/14
to chromi...@chromium.org, rpa...@chromium.org, Hoa V. Dinh
The permissions are now set using a top level manifest key:

"sockets": {
  "tcp": {
     "connect": "*:*"

David Brodbeck

unread,
Feb 1, 2014, 2:22:14 PM2/1/14
to rpa...@chromium.org, Chromium Apps, Hoa V. Dinh

Aha, thanks. I tried to RTFM but couldn't find docs for the new API...probably looked in the wrong place.

agus.mu...@gmail.com

unread,
Feb 2, 2014, 10:54:01 AM2/2/14
to David Brodbeck, chromi...@chromium.org, rpa...@chromium.org, Hoa V. Dinh
Powered by Telkomsel BlackBerry®

From: David Brodbeck <gu...@gull.us>
Date: Sat, 1 Feb 2014 11:22:14 -0800
Cc: Chromium Apps<chromi...@chromium.org>; Hoa V. Dinh<d...@chromium.org>
Subject: Re: [cws-apps] chrome sockets sometimes can't bind to a port, even after reloading the packaged app
Reply all
Reply to author
Forward
0 new messages