[IMP] OSX handling of socket shutdown in TinySocketClientThread

When the client closes its socket, on OSX it closes the server one as well, leading to an errno.ENOTCONN when trying to shut it down.

Also use the unified socket-closing function to handle tinysocket

bzr revid: xmo@openerp.com-20110616102624-vixxow6twsx7j84s
This commit is contained in:
Xavier Morel 2011-06-16 12:26:24 +02:00
parent abb606aa7c
commit 012c93ae40
3 changed files with 28 additions and 30 deletions

View File

@ -26,22 +26,42 @@
import cgitb import cgitb
import errno import errno
import heapq
import logging import logging
import logging.handlers import logging.handlers
import os import os
import platform
import release
import socket import socket
import sys import sys
import threading import threading
import time import time
import release
from pprint import pformat
import warnings import warnings
import heapq from pprint import pformat
# TODO modules that import netsvc only for things from loglevels must be changed to use loglevels. # TODO modules that import netsvc only for things from loglevels must be changed to use loglevels.
from loglevels import * from loglevels import *
import tools import tools
def close_socket(sock):
""" Closes a socket instance cleanly
:param sock: the network socket to close
:type sock: socket.socket
"""
try:
sock.shutdown(socket.SHUT_RDWR)
except socket.error, e:
## On OSX, socket shutdowns both sides if any side closes it
## causing an error 57 'Socket is not connected' on shutdown
## of the other side (or something), see
## http://bugs.python.org/issue4397
## note: stdlib fixed test, not behavior
if e.errno != errno.ENOTCONN or platform.system() != 'Darwin':
raise
sock.close()
class Service(object): class Service(object):
""" Base class for *Local* services """ Base class for *Local* services
@ -381,19 +401,7 @@ class Server:
return '\n'.join(res) return '\n'.join(res)
def _close_socket(self): def _close_socket(self):
if os.name != 'nt': close_socket(self.socket)
try:
self.socket.shutdown(getattr(socket, 'SHUT_RDWR', 2))
except socket.error, e:
if e.errno != errno.ENOTCONN: raise
# OSX, socket shutdowns both sides if any side closes it
# causing an error 57 'Socket is not connected' on shutdown
# of the other side (or something), see
# http://bugs.python.org/issue4397
self.__logger.debug(
'"%s" when shutting down server socket, '
'this is normal under OS X', e)
self.socket.close()
class OpenERPDispatcherException(Exception): class OpenERPDispatcherException(Exception):
def __init__(self, exception, traceback): def __init__(self, exception, traceback):

View File

@ -45,16 +45,6 @@ class TinySocketClientThread(threading.Thread, netsvc.OpenERPDispatcher):
self.sock.settimeout(1200) self.sock.settimeout(1200)
self.threads = threads self.threads = threads
def __del__(self):
if self.sock:
try:
self.socket.shutdown(
getattr(socket, 'SHUT_RDWR', 2))
except Exception:
pass
# That should garbage-collect and close it, too
self.sock = None
def run(self): def run(self):
self.running = True self.running = True
try: try:
@ -93,8 +83,7 @@ class TinySocketClientThread(threading.Thread, netsvc.OpenERPDispatcher):
logging.getLogger('web-services').exception("netrpc: cannot deliver exception message to client") logging.getLogger('web-services').exception("netrpc: cannot deliver exception message to client")
break break
self.sock.shutdown(socket.SHUT_RDWR) netsvc.close_socket(self.sock)
self.sock.close()
self.sock = None self.sock = None
self.threads.remove(self) self.threads.remove(self)
self.running = False self.running = False

View File

@ -24,6 +24,8 @@ import cPickle
import cStringIO import cStringIO
import marshal import marshal
import netsvc
class Myexception(Exception): class Myexception(Exception):
""" """
custome exception object store custome exception object store
@ -56,8 +58,7 @@ class mysocket:
self.sock.connect((host, int(port))) self.sock.connect((host, int(port)))
def disconnect(self): def disconnect(self):
self.sock.shutdown(socket.SHUT_RDWR) netsvc.close_socket(self.sock)
self.sock.close()
def mysend(self, msg, exception=False, traceback=None): def mysend(self, msg, exception=False, traceback=None):
msg = cPickle.dumps([msg,traceback]) msg = cPickle.dumps([msg,traceback])