This issue tracker has been migrated to GitHub, and is currently read-only.
For more information, see the GitHub FAQs in the Python's Developer Guide.

classification
Title: socket error [Errno 10013] when creating SMTP object
Type: behavior Stage:
Components: Library (Lib), Windows Versions: Python 3.2
process
Status: closed Resolution: works for me
Dependencies: Superseder:
Assigned To: Nosy List: Jimbofbx, loewis, pitrou, tim.golden
Priority: normal Keywords:

Created on 2012-08-24 17:42 by Jimbofbx, last changed 2022-04-11 14:57 by admin. This issue is now closed.

Messages (15)
msg169055 - (view) Author: James Hutchison (Jimbofbx) Date: 2012-08-24 17:42
Windows 7 64-bit, Python 3.2.3

This is a very odd issue and I haven't figured out what caused it. I have a python script that runs continuously. When it receives a request to do a task, it creates a new thread (not a new process), does the task, then sends out an e-mail to indicate it was done. It doesn't do this a lot (maybe 10 - 30 times a day). This is all the script does.

Well today, it randomly broke. It was working fine, then suddenly I was getting the following error when it would create an SMTP object:

socket.error: [Errno 10013] An attempt was made to access a socket in a way forbidden by its access permissions

What I found was, even after trying a different script that did nothing but create a simple SMTP connection to localhost, running with admin privileges, and even after rebooting the machine, I was getting this error. I checked my firewall and didn't see any changes (I share a group policy so I do not have full control). I also tried the script on a different machine and found no issue. The issue also persisted between IDLE and simply running python.exe

When I tried to debug the issue, I discovered the following piece of code made the issue go away:

s = socket.socket()
s.bind(('',50007))
s.listen(1);
s.close();

And it hasn't come back since. I've tried to reproduce the circumstances that my script was running by creating SMTP instances in a loop but haven't been able to recreate the error. Checking my log, there isn't anything abnormal that occurred just before this issue (like attempting to do the task several times at once or something).
msg169061 - (view) Author: Martin v. Löwis (loewis) * (Python committer) Date: 2012-08-24 17:58
As this is an error reported by Windows, it *very* unlikely is an issue with Python. Instead, it's a reaction that Windows produced to some sequence of events.

My guess is that another process had the address in use, apparently, Windows then reports WSAEACCESS in certain cases instead of the expected WSAEADDRINUSE.

What specific socket operation was the one that failed?
msg169079 - (view) Author: James Hutchison (Jimbofbx) Date: 2012-08-24 19:46
This is the traceback I was getting where it was just a script that simply made an SMTP connection then closed it. This fails before it attempts to connect to the server.

Traceback (most recent call last):
  File "C:\tmp\manysmtptest.py", line 8, in <module>
    main();
  File "C:\tmp\manysmtptest.py", line 4, in main
    a = SMTP(myserver);
  File "C:\Python32\lib\smtplib.py", line 259, in __init__
    (code, msg) = self.connect(host, port)
  File "C:\Python32\lib\smtplib.py", line 319, in connect
    self.sock = self._get_socket(host, port, self.timeout)
  File "C:\Python32\lib\smtplib.py", line 294, in _get_socket
    return socket.create_connection((host, port), timeout)
  File "C:\Python32\lib\socket.py", line 404, in create_connection
    raise err
  File "C:\Python32\lib\socket.py", line 395, in create_connection
    sock.connect(sa)
socket.error: [Errno 10013] An attempt was made to access a socket in a way forbidden by its access permissions

What I don't get is why rebooting didn't fix the problem. You'd think Python or Windows issue, things would resolve themselves after a reboot. All the other programs I was using seemed to work fine.
msg169080 - (view) Author: Martin v. Löwis (loewis) * (Python committer) Date: 2012-08-24 20:18
It's very easy to see why it survives a reboot. If there is a collision with some other process, that process restarts, recreating the collision. Things may depend on timing, so it may happen on some reboots and not on others (e.g. if the colliding process has picked some other port).

Closing this as "works for me".
msg169081 - (view) Author: James Hutchison (Jimbofbx) Date: 2012-08-24 20:36
That makes no sense. Why does:

s = socket.socket()
s.bind(('',50007))
s.listen(1);
s.close();

fix the issue then?

Re-opening, this issue should be understood because having such an operation randomly fail is unacceptable for a production system. How does python choose a port to open a connection on? If windows reports the wrong error then shouldn't python try a different port number anyways (considering I have no control over what port Python chooses to open a connection on)?
msg169084 - (view) Author: Antoine Pitrou (pitrou) * (Python committer) Date: 2012-08-24 21:03
> s.bind(('',50007))

How did you find out 50007? Is it just a random number you chose?
msg169086 - (view) Author: James Hutchison (Jimbofbx) Date: 2012-08-24 21:06
It's from the example.

http://docs.python.org/library/socket.html#example
msg169087 - (view) Author: Antoine Pitrou (pitrou) * (Python committer) Date: 2012-08-24 21:09
According to the MSDN doc for connect():

WSAEACCES: An attempt to connect a datagram socket to broadcast address failed because setsockopt option SO_BROADCAST is not enabled.

However, this implies that `getaddrinfo(host, port, 0, SOCK_STREAM)` (in socket.create_connection) returned parameters for a datagram socket...
msg169088 - (view) Author: Antoine Pitrou (pitrou) * (Python committer) Date: 2012-08-24 21:13
Oh, a random Google search brought the following comment from the chromium source code (it seems):
“connect fails with WSAEACCES when Windows Firewall blocks the connection”.

This sounds like a likelier explanation than the previous one.
msg169091 - (view) Author: James Hutchison (Jimbofbx) Date: 2012-08-24 21:35
The firewall is disabled for my machine.

So the options are:
1. Port was in-use: possible except that is normally a different error
2. Port was firewalled: firewall was disabled
3. Port mis-use: not likely because this wouldn't be random
4. Port was in restricted port range for some reason: admin privileges did not resolve

#1 seems the most plausible so far
msg169092 - (view) Author: Antoine Pitrou (pitrou) * (Python committer) Date: 2012-08-24 21:42
By the way, please check the return value of getaddrinfo() for your SMTP server:

>>> socket.getaddrinfo("www.gmail.com", 25, 0, socket.SOCK_STREAM)
[(2, 1, 6, '', ('74.125.230.213', 25)), (2, 1, 6, '', ('74.125.230.214', 25)), (10, 1, 6, '', ('2a00:1450:4007:802::1016', 25, 0, 0))]

and then try to connect() to each of the addresses. If one of the addresses gives WSAEACCES when connecting, you've got the explanation.
msg169095 - (view) Author: James Hutchison (Jimbofbx) Date: 2012-08-24 21:55
I can connect to all of the IPs for my server without issue.

Found this:

Another possible reason for the WSAEACCES error is that when the bind function is called (on Windows NT 4.0 with SP4 and later), another application, service, or kernel mode driver is bound to the same address with exclusive access. Such exclusive access is a new feature of Windows NT 4.0 with SP4 and later, and is implemented by using the SO_EXCLUSIVEADDRUSE option.

So that explains why you may see either WSAEADDRINUSE or WSAEACCESS

So at this point, I think the question is - how does python choose an outgoing port?
msg169099 - (view) Author: Martin v. Löwis (loewis) * (Python committer) Date: 2012-08-24 23:39
The Python API maps nearly 1:1 to the winsock API. So the Python code literally translates to the equivalent C code (with *very* minor deviations e.g. involving the conversion of string addresses in numeric addresses).

Please leave the issue closed unless you can provide substantial evidence that there is a bug in Python.

I disagree that the issue needs to be understood. This is only an acceptable request if you can provide a reproducible test cases, which you (currently) cannot. Anybody wanting to understand the issue might need physical access to your system, which is not feasible.
msg169101 - (view) Author: James Hutchison (Jimbofbx) Date: 2012-08-25 00:12
Looks to me like python grabs an outgoing port number via unrandom means and if it happens to map to a port taken by a service that demands exclusive access, then it returns the WSAEACCESS error instead of WSAEADDRINUSE. Because this is a fairly new "feature" in windows (NT 4.0 w/ SP3), Python does not properly account for it by simply trying another port like it would if it got WSAEADDRINUSE

Arguably this would affect all aspects of Python that uses sockets.

The function in question seems to be:

getaddrinfo(host, port, 0, SOCK_STREAM)

Which, if I'm understanding the code correctly, returns the source address used to make the connection in this instance. Unfortunately, that function is in a compiled binary so I don't know how it works.

If windows is responsible for giving the bad port number, I would argue that Python still needs to account for the problem since this is obviously a major issue if it happens to someone. The fact that you mentioned that the cause is the fact WSAEADDRINUSE isn't the error, then that seems to imply Python is doing the selection.

If python is using a windows library to get outgoing port, it is also possible that maybe that library is outdated and it needs to use a newer one.
msg169103 - (view) Author: Antoine Pitrou (pitrou) * (Python committer) Date: 2012-08-25 00:22
> Looks to me like python grabs an outgoing port number via unrandom means

Python does not grab an outgoing port number, its lets the OS choose one (via connect()). The only thing to watch out for would be whether you let many connections open (perhaps there's a per-process limit that is reached).

> Which, if I'm understanding the code correctly, returns the source
> address used to make the connection in this instance.

getaddrinfo() does not do that. It is simply a wrapper around the C runtime library's getaddrinfo(), for which you can find information on the Web (for both the Windows and POSIX versions of it).

> If windows is responsible for giving the bad port number, I would argue
> that Python still needs to account for the problem since this is obviously 
> a major issue if it happens to someone.

It might be a major issue for whoever encounters the issue but, as Martin said, Python cannot do anything else than bubble up the exception for you to handle.

Since this seems to be a fairly involved Windows issue (rather than a Python bug), I suggest you ask for help on a help forum with Windows experts.
History
Date User Action Args
2022-04-11 14:57:35adminsetgithub: 59983
2012-08-25 00:22:38pitrousetstatus: open -> closed

messages: + msg169103
2012-08-25 00:21:44Jimbofbxsetcomponents: + Windows
2012-08-25 00:12:51Jimbofbxsetmessages: + msg169101
2012-08-24 23:59:58brian.curtinsetnosy: - brian.curtin
2012-08-24 23:58:42Jimbofbxsetstatus: closed -> open
2012-08-24 23:39:32loewissetstatus: open -> closed

messages: + msg169099
2012-08-24 21:55:40Jimbofbxsetmessages: + msg169095
2012-08-24 21:42:41pitrousetmessages: + msg169092
2012-08-24 21:35:05Jimbofbxsetmessages: + msg169091
2012-08-24 21:13:34pitrousetmessages: + msg169088
2012-08-24 21:09:25pitrousetmessages: + msg169087
2012-08-24 21:06:07Jimbofbxsetmessages: + msg169086
2012-08-24 21:03:20pitrousetnosy: + tim.golden, brian.curtin, pitrou
messages: + msg169084
2012-08-24 20:36:16Jimbofbxsetstatus: closed -> open

messages: + msg169081
2012-08-24 20:18:06loewissetstatus: open -> closed
resolution: works for me
messages: + msg169080
2012-08-24 19:46:30Jimbofbxsetmessages: + msg169079
2012-08-24 17:58:51loewissetnosy: + loewis
messages: + msg169061
2012-08-24 17:42:16Jimbofbxcreate