1
# -*- coding: utf-8 -*-
3
# Copyright (C) 2005 Ole André Vadla Ravnås <oleavr@gmail.com>
4
# Copyright (C) 2006-2007 Ali Sabil <ali.sabil@gmail.com>
5
# Copyright (C) 2007 Johann Prieur <johann.prieur@gmail.com>
7
# This program is free software; you can redistribute it and/or modify
8
# it under the terms of the GNU General Public License as published by
9
# the Free Software Foundation; either version 2 of the License, or
10
# (at your option) any later version.
12
# This program is distributed in the hope that it will be useful,
13
# but WITHOUT ANY WARRANTY; without even the implied warranty of
14
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15
# GNU General Public License for more details.
17
# You should have received a copy of the GNU General Public License
18
# along with this program; if not, write to the Free Software
19
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
21
from pymsn.gnet.constants import *
22
from iochannel import GIOChannelClient
26
import OpenSSL.SSL as OpenSSL
28
__all__ = ['SSLSocketClient']
30
class SSLSocketClient(GIOChannelClient):
31
"""Asynchronous Socket client class.
33
@sort: __init__, open, send, close
34
@undocumented: do_*, _watch_*, __io_*, _connect_done_handler
38
def __init__(self, host, port, domain=AF_INET, type=SOCK_STREAM):
39
GIOChannelClient.__init__(self, host, port, domain, type)
41
def _pre_open(self, sock=None):
43
sock = socket.socket(self._domain, self._type)
45
sock.setsockopt(socket.SOL_SOCKET, socket.SO_KEEPALIVE, 1)
46
except AttributeError:
48
context = OpenSSL.Context(OpenSSL.SSLv23_METHOD)
49
ssl_sock = OpenSSL.Connection(context, sock)
50
GIOChannelClient._pre_open(self, ssl_sock)
53
GIOChannelClient._post_open(self)
54
if self._transport.getsockopt(socket.SOL_SOCKET, socket.SO_ERROR) == 0:
55
self._watch_set_cond(gobject.IO_IN | gobject.IO_PRI | gobject.IO_OUT |
56
gobject.IO_ERR | gobject.IO_HUP)
58
self.emit("error", IoError.CONNECTION_FAILED)
59
self._status = IoStatus.CLOSED
62
def _io_channel_handler(self, chan, cond):
63
if self._status == IoStatus.CLOSED:
65
if self._status == IoStatus.OPENING:
67
self._transport.do_handshake()
68
except (OpenSSL.WantX509LookupError,
69
OpenSSL.WantReadError, OpenSSL.WantWriteError):
71
except (OpenSSL.ZeroReturnError, OpenSSL.SysCallError):
72
self.emit("error", IoError.SSL_CONNECTION_FAILED)
76
self._status = IoStatus.OPEN
77
elif self._status == IoStatus.OPEN:
78
if cond & (gobject.IO_IN | gobject.IO_PRI):
80
buf = self._transport.recv(2048)
81
except (OpenSSL.WantX509LookupError,
82
OpenSSL.WantReadError, OpenSSL.WantWriteError):
84
except (OpenSSL.ZeroReturnError, OpenSSL.SysCallError):
87
self.emit("received", buf, len(buf))
89
if cond & (gobject.IO_ERR | gobject.IO_HUP):
93
if cond & gobject.IO_OUT:
94
if len(self._outgoing_queue) > 0: # send next item
95
item = self._outgoing_queue[0]
97
ret = self._transport.send(item.read())
98
except (OpenSSL.WantX509LookupError,
99
OpenSSL.WantReadError, OpenSSL.WantWriteError):
101
except (OpenSSL.ZeroReturnError, OpenSSL.SysCallError):
105
if item.is_complete(): # sent item
106
self.emit("sent", item.buffer, item.size)
108
del self._outgoing_queue[0]
110
if len(self._outgoing_queue) == 0:
111
self._watch_remove_cond(gobject.IO_OUT)
113
self._watch_remove_cond(gobject.IO_OUT)
117
gobject.type_register(SSLSocketClient)