OpenSSL support. This is based on patches for a version of SSLeay by

Brian E Gallew, which were improved and adapted to OpenSSL 0.9.4 by
Laszlo Kovacs of HP.  Both have kindly given permission to include
the patches in the Python distribution.  Final formatting by GvR.
This commit is contained in:
Guido van Rossum 1999-12-07 21:37:17 +00:00
parent 5274c336f5
commit 09c8b6c3e4
3 changed files with 439 additions and 19 deletions

View File

@ -28,17 +28,48 @@ second request to the same server, you create a new HTTP object.
connection for each request.) connection for each request.)
""" """
import os
import socket import socket
import string import string
import mimetools import mimetools
try:
from cStringIO import StringIO
except:
from StringIO import StringIO
HTTP_VERSION = 'HTTP/1.0' HTTP_VERSION = 'HTTP/1.0'
HTTP_PORT = 80 HTTP_PORT = 80
HTTPS_PORT = 443
class FakeSocket:
def __init__(self, sock, ssl):
self.__sock = sock
self.__ssl = ssl
return
def makefile(self, mode): # hopefully, never have to write
msgbuf = ""
while 1:
try:
msgbuf = msgbuf + self.__ssl.read()
except socket.sslerror, msg:
break
return StringIO(msgbuf)
def send(self, stuff, flags = 0):
return self.__ssl.write(stuff)
def recv(self, len = 1024, flags = 0):
return self.__ssl.read(len)
def __getattr__(self, attr):
return getattr(self.__sock, attr)
class HTTP: class HTTP:
"""This class manages a connection to an HTTP server.""" """This class manages a connection to an HTTP server."""
def __init__(self, host = '', port = 0): def __init__(self, host = '', port = 0, **x509):
"""Initialize a new instance. """Initialize a new instance.
If specified, `host' is the name of the remote host to which If specified, `host' is the name of the remote host to which
@ -46,10 +77,12 @@ class HTTP:
to connect. By default, httplib.HTTP_PORT is used. to connect. By default, httplib.HTTP_PORT is used.
""" """
self.key_file = x509.get('key_file')
self.cert_file = x509.get('cert_file')
self.debuglevel = 0 self.debuglevel = 0
self.file = None self.file = None
if host: self.connect(host, port) if host: self.connect(host, port)
def set_debuglevel(self, debuglevel): def set_debuglevel(self, debuglevel):
"""Set the debug output level. """Set the debug output level.
@ -58,10 +91,10 @@ class HTTP:
""" """
self.debuglevel = debuglevel self.debuglevel = debuglevel
def connect(self, host, port = 0): def connect(self, host, port = 0):
"""Connect to a host on a given port. """Connect to a host on a given port.
Note: This method is automatically invoked by __init__, Note: This method is automatically invoked by __init__,
if a host is specified during instantiation. if a host is specified during instantiation.
@ -77,12 +110,12 @@ class HTTP:
self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
if self.debuglevel > 0: print 'connect:', (host, port) if self.debuglevel > 0: print 'connect:', (host, port)
self.sock.connect(host, port) self.sock.connect(host, port)
def send(self, str): def send(self, str):
"""Send `str' to the server.""" """Send `str' to the server."""
if self.debuglevel > 0: print 'send:', `str` if self.debuglevel > 0: print 'send:', `str`
self.sock.send(str) self.sock.send(str)
def putrequest(self, request, selector): def putrequest(self, request, selector):
"""Send a request to the server. """Send a request to the server.
@ -94,7 +127,7 @@ class HTTP:
if not selector: selector = '/' if not selector: selector = '/'
str = '%s %s %s\r\n' % (request, selector, HTTP_VERSION) str = '%s %s %s\r\n' % (request, selector, HTTP_VERSION)
self.send(str) self.send(str)
def putheader(self, header, *args): def putheader(self, header, *args):
"""Send a request header line to the server. """Send a request header line to the server.
@ -103,14 +136,14 @@ class HTTP:
""" """
str = '%s: %s\r\n' % (header, string.joinfields(args,'\r\n\t')) str = '%s: %s\r\n' % (header, string.joinfields(args,'\r\n\t'))
self.send(str) self.send(str)
def endheaders(self): def endheaders(self):
"""Indicate that the last header line has been sent to the server.""" """Indicate that the last header line has been sent to the server."""
self.send('\r\n') self.send('\r\n')
def getreply(self): def getreply(self):
"""Get a reply from the server. """Get a reply from the server.
Returns a tuple consisting of: Returns a tuple consisting of:
- server response code (e.g. '200' if all goes well) - server response code (e.g. '200' if all goes well)
- server response string corresponding to response code - server response string corresponding to response code
@ -136,7 +169,7 @@ class HTTP:
errmsg = string.strip(msg) errmsg = string.strip(msg)
self.headers = mimetools.Message(self.file, 0) self.headers = mimetools.Message(self.file, 0)
return errcode, errmsg, self.headers return errcode, errmsg, self.headers
def getfile(self): def getfile(self):
"""Get a file object from which to receive data from the HTTP server. """Get a file object from which to receive data from the HTTP server.
@ -145,7 +178,7 @@ class HTTP:
""" """
return self.file return self.file
def close(self): def close(self):
"""Close the connection to the HTTP server.""" """Close the connection to the HTTP server."""
if self.file: if self.file:
@ -155,6 +188,31 @@ class HTTP:
self.sock.close() self.sock.close()
self.sock = None self.sock = None
if hasattr(socket, "ssl"):
class HTTPS(HTTP):
"""This class allows communication via SSL."""
def connect(self, host, port = 0):
"""Connect to a host on a given port.
Note: This method is automatically invoked by __init__,
if a host is specified during instantiation.
"""
if not port:
i = string.find(host, ':')
if i >= 0:
host, port = host[:i], host[i+1:]
try: port = string.atoi(port)
except string.atoi_error:
raise socket.error, "nonnumeric port"
if not port: port = HTTPS_PORT
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
if self.debuglevel > 0: print 'connect:', (host, port)
sock.connect(host, port)
ssl = socket.ssl(sock, self.key_file, self.cert_file)
self.sock = FakeSocket(sock, ssl)
def test(): def test():
"""Test this module. """Test this module.
@ -170,6 +228,7 @@ def test():
dl = 0 dl = 0
for o, a in opts: for o, a in opts:
if o == '-d': dl = dl + 1 if o == '-d': dl = dl + 1
print "testing HTTP..."
host = 'www.python.org' host = 'www.python.org'
selector = '/' selector = '/'
if args[0:]: host = args[0] if args[0:]: host = args[0]
@ -187,6 +246,26 @@ def test():
for header in headers.headers: print string.strip(header) for header in headers.headers: print string.strip(header)
print print
print h.getfile().read() print h.getfile().read()
if hasattr(socket, "ssl"):
print "-"*40
print "testing HTTPS..."
host = 'synergy.as.cmu.edu'
selector = '/~geek/'
if args[0:]: host = args[0]
if args[1:]: selector = args[1]
h = HTTPS()
h.set_debuglevel(dl)
h.connect(host)
h.putrequest('GET', selector)
h.endheaders()
errcode, errmsg, headers = h.getreply()
print 'errcode =', errcode
print 'errmsg =', errmsg
print
if headers:
for header in headers.headers: print string.strip(header)
print
print h.getfile().read()
if __name__ == '__main__': if __name__ == '__main__':

View File

@ -27,7 +27,7 @@ import os
import sys import sys
__version__ = '1.11' # XXX This version is not always updated :-( __version__ = '1.12' # XXX This version is not always updated :-(
MAXFTPCACHE = 10 # Trim the ftp cache beyond this size MAXFTPCACHE = 10 # Trim the ftp cache beyond this size
@ -81,11 +81,13 @@ class URLopener:
__tempfiles = None __tempfiles = None
# Constructor # Constructor
def __init__(self, proxies=None): def __init__(self, proxies=None, **x509):
if proxies is None: if proxies is None:
proxies = getproxies() proxies = getproxies()
assert hasattr(proxies, 'has_key'), "proxies must be a mapping" assert hasattr(proxies, 'has_key'), "proxies must be a mapping"
self.proxies = proxies self.proxies = proxies
self.key_file = x509.get('key_file')
self.cert_file = x509.get('cert_file')
server_version = "Python-urllib/%s" % __version__ server_version = "Python-urllib/%s" % __version__
self.addheaders = [('User-agent', server_version)] self.addheaders = [('User-agent', server_version)]
self.__tempfiles = [] self.__tempfiles = []
@ -144,6 +146,7 @@ class URLopener:
host, selector = splithost(proxy) host, selector = splithost(proxy)
url = (host, fullurl) # Signal special case to open_*() url = (host, fullurl) # Signal special case to open_*()
name = 'open_' + type name = 'open_' + type
self.type = type
if '-' in name: if '-' in name:
# replace - with _ # replace - with _
name = string.join(string.split(name, '-'), '_') name = string.join(string.split(name, '-'), '_')
@ -294,6 +297,42 @@ class URLopener:
fp.close() fp.close()
raise IOError, ('http error', errcode, errmsg, headers) raise IOError, ('http error', errcode, errmsg, headers)
# Use HTTPS protocol
if hasattr(socket, "ssl"):
def open_https(self, url):
import httplib
if type(url) is type(""):
host, selector = splithost(url)
user_passwd, host = splituser(host)
else:
host, selector = url
urltype, rest = splittype(selector)
if string.lower(urltype) == 'https':
realhost, rest = splithost(rest)
user_passwd, realhost = splituser(realhost)
if user_passwd:
selector = "%s://%s%s" % (urltype, realhost, rest)
print "proxy via https:", host, selector
if not host: raise IOError, ('https error', 'no host given')
if user_passwd:
import base64
auth = string.strip(base64.encodestring(user_passwd))
else:
auth = None
h = httplib.HTTPS(host, 0,
key_file=self.key_file,
cert_file=self.cert_file)
h.putrequest('GET', selector)
if auth: h.putheader('Authorization: Basic %s' % auth)
for args in self.addheaders: apply(h.putheader, args)
h.endheaders()
errcode, errmsg, headers = h.getreply()
fp = h.getfile()
if errcode == 200:
return addinfourl(fp, headers, url)
else:
return self.http_error(url, fp, errcode, errmsg, headers)
# Use Gopher protocol # Use Gopher protocol
def open_gopher(self, url): def open_gopher(self, url):
import gopherlib import gopherlib
@ -477,7 +516,8 @@ class FancyURLopener(URLopener):
if match: if match:
scheme, realm = match.groups() scheme, realm = match.groups()
if string.lower(scheme) == 'basic': if string.lower(scheme) == 'basic':
return self.retry_http_basic_auth(url, realm, data) name = 'retry_' + self.type + '_basic_auth'
return getattr(self,name)(url, realm)
def retry_http_basic_auth(self, url, realm, data): def retry_http_basic_auth(self, url, realm, data):
host, selector = splithost(url) host, selector = splithost(url)
@ -488,6 +528,16 @@ class FancyURLopener(URLopener):
host = user + ':' + passwd + '@' + host host = user + ':' + passwd + '@' + host
newurl = 'http://' + host + selector newurl = 'http://' + host + selector
return self.open(newurl, data) return self.open(newurl, data)
def retry_https_basic_auth(self, url, realm):
host, selector = splithost(url)
i = string.find(host, '@') + 1
host = host[i:]
user, passwd = self.get_user_passwd(host, realm, i)
if not (user or passwd): return None
host = user + ':' + passwd + '@' + host
newurl = '//' + host + selector
return self.open_https(newurl)
def get_user_passwd(self, host, realm, clear_cache = 0): def get_user_passwd(self, host, realm, clear_cache = 0):
key = realm + '@' + string.lower(host) key = realm + '@' + string.lower(host)
@ -630,8 +680,8 @@ class addbase:
self.fp = fp self.fp = fp
self.read = self.fp.read self.read = self.fp.read
self.readline = self.fp.readline self.readline = self.fp.readline
self.readlines = self.fp.readlines if hasattr(self.fp, "readlines"): self.readlines = self.fp.readlines
self.fileno = self.fp.fileno if hasattr(self.fp, "fileno"): self.fileno = self.fp.fileno
def __repr__(self): def __repr__(self):
return '<%s at %s whose fp = %s>' % (self.__class__.__name__, return '<%s at %s whose fp = %s>' % (self.__class__.__name__,
`id(self)`, `self.fp`) `id(self)`, `self.fp`)
@ -1015,6 +1065,8 @@ def test(args=[]):
## 'gopher://gopher.micro.umn.edu/1/', ## 'gopher://gopher.micro.umn.edu/1/',
'http://www.python.org/index.html', 'http://www.python.org/index.html',
] ]
if hasattr(URLopener, "open_https"):
args.append('https://synergy.as.cmu.edu/~geek/')
try: try:
for url in args: for url in args:
print '-'*10, url, '-'*10 print '-'*10, url, '-'*10

View File

@ -31,6 +31,8 @@ PERFORMANCE OF THIS SOFTWARE.
/* Socket module */ /* Socket module */
/* SSL support based on patches by Brian E Gallew and Laszlo Kovacs */
/* /*
This module provides an interface to Berkeley socket IPC. This module provides an interface to Berkeley socket IPC.
@ -56,6 +58,7 @@ Module interface:
- socket.AF_INET, socket.SOCK_STREAM, etc.: constants from <socket.h> - socket.AF_INET, socket.SOCK_STREAM, etc.: constants from <socket.h>
- socket.inet_aton(IP address) -> 32-bit packed IP representation - socket.inet_aton(IP address) -> 32-bit packed IP representation
- socket.inet_ntoa(packed IP) -> IP address string - socket.inet_ntoa(packed IP) -> IP address string
- socket.ssl(socket, keyfile, certfile) -> new ssl object
- an Internet socket address is a pair (hostname, port) - an Internet socket address is a pair (hostname, port)
where hostname can be anything recognized by gethostbyname() where hostname can be anything recognized by gethostbyname()
(including the dd.dd.dd.dd notation) and port is in host byte order (including the dd.dd.dd.dd notation) and port is in host byte order
@ -190,6 +193,14 @@ int shutdown( int, int );
#include <GUSI.h> #include <GUSI.h>
#endif #endif
#ifdef USE_SSL
#include "rsa.h"
#include "crypto.h"
#include "x509.h"
#include "pem.h"
#include "ssl.h"
#include "err.h"
#endif /* USE_SSL */
/* Here we have some hacks to choose between K&R or ANSI style function /* Here we have some hacks to choose between K&R or ANSI style function
definitions. For NT to build this as an extension module (ie, DLL) definitions. For NT to build this as an extension module (ie, DLL)
@ -253,6 +264,10 @@ fnname( arg1name, arg2name, arg3name, arg4name ) \
static PyObject *PySocket_Error; static PyObject *PySocket_Error;
#ifdef USE_SSL
static PyObject *SSLErrorObject;
#endif /* USE_SSL */
/* Convenience function to raise an error according to errno /* Convenience function to raise an error according to errno
and return a NULL pointer from a function. */ and return a NULL pointer from a function. */
@ -324,7 +339,30 @@ typedef struct {
} sock_addr; } sock_addr;
} PySocketSockObject; } PySocketSockObject;
#ifdef USE_SSL
typedef struct {
PyObject_HEAD
PySocketSockObject *Socket; /* Socket on which we're layered */
PyObject *x_attr; /* Attributes dictionary */
SSL_CTX* ctx;
SSL* ssl;
X509* server_cert;
BIO* sbio;
char server[256];
char issuer[256];
} SSLObject;
staticforward PyTypeObject SSL_Type;
staticforward int SSL_setattr(SSLObject *self, char *name, PyObject *v);
staticforward PyObject *SSL_SSLwrite(SSLObject *self, PyObject *args);
staticforward PyObject *SSL_SSLread(SSLObject *self, PyObject *args);
#define SSLObject_Check(v) ((v)->ob_type == &SSL_Type)
#endif /* USE_SSL */
/* A forward reference to the Socktype type object. /* A forward reference to the Socktype type object.
The Socktype variable contains pointers to various functions, The Socktype variable contains pointers to various functions,
some of which call newsockobject(), which uses Socktype, so some of which call newsockobject(), which uses Socktype, so
@ -1874,6 +1912,242 @@ BUILD_FUNC_DEF_2(PySocket_inet_ntoa, PyObject *, self, PyObject *, args)
return PyString_FromString(inet_ntoa(packed_addr)); return PyString_FromString(inet_ntoa(packed_addr));
} }
#ifdef USE_SSL
/* This is a C function to be called for new object initialization */
static SSLObject *
BUILD_FUNC_DEF_3(newSSLObject,
PySocketSockObject *,Sock, char*,key_file, char*,cert_file)
{
SSLObject *self;
char *str;
#if 0
meth=SSLv23_client_method();
meth=SSLv3_client_method();
meth=SSLv2_client_method();
#endif
self = PyObject_NEW(SSLObject, &SSL_Type); /* Create new object */
if (self == NULL){
PyErr_SetObject(SSLErrorObject,
PyString_FromString("newSSLObject error"));
return NULL;
}
memset(self->server, NULL, sizeof(char) * 256);
memset(self->issuer, NULL, sizeof(char) * 256);
self->x_attr = PyDict_New();
self->ctx = SSL_CTX_new(SSLv23_method()); /* Set up context */
if (self->ctx == NULL) {
PyErr_SetObject(SSLErrorObject,
PyString_FromString("SSL_CTX_new error"));
PyMem_DEL(self);
return NULL;
}
if ( (key_file && !cert_file) || (!key_file && cert_file) )
{
PyErr_SetObject(SSLErrorObject,
PyString_FromString(
"Both the key & certificate files must be specified"));
PyMem_DEL(self);
return NULL;
}
if (key_file && cert_file)
{
if (SSL_CTX_use_PrivateKey_file(self->ctx, key_file,
SSL_FILETYPE_PEM) < 1)
{
PyErr_SetObject(SSLErrorObject,
PyString_FromString(
"SSL_CTX_use_PrivateKey_file error"));
PyMem_DEL(self);
return NULL;
}
if (SSL_CTX_use_certificate_chain_file(self->ctx,
cert_file) < 1)
{
PyErr_SetObject(SSLErrorObject,
PyString_FromString(
"SSL_CTX_use_certificate_chain_file error"));
PyMem_DEL(self);
return NULL;
}
}
SSL_CTX_set_verify(self->ctx,
SSL_VERIFY_NONE, NULL); /* set verify lvl */
self->ssl = SSL_new(self->ctx); /* New ssl struct */
SSL_set_fd(self->ssl, Sock->sock_fd); /* Set the socket for SSL */
SSL_set_connect_state(self->ssl);
if ((SSL_connect(self->ssl)) == -1) {
/* Actually negotiate SSL connection */
PyErr_SetObject(SSLErrorObject,
PyString_FromString("SSL_connect error"));
PyMem_DEL(self);
return NULL;
}
self->ssl->debug = 1;
if ((self->server_cert = SSL_get_peer_certificate(self->ssl))) {
X509_NAME_oneline(X509_get_subject_name(self->server_cert),
self->server, 256);
X509_NAME_oneline(X509_get_issuer_name(self->server_cert),
self->issuer, 256);
}
self->x_attr = NULL;
self->Socket = Sock;
Py_INCREF(self->Socket);
return self;
}
/* This is the Python function called for new object initialization */
static PyObject *
BUILD_FUNC_DEF_2(PySocket_ssl, PyObject *, self, PyObject *, args)
{
SSLObject *rv;
PySocketSockObject *Sock;
char *key_file;
char *cert_file;
if (!PyArg_ParseTuple(args, "O!zz",
&PySocketSock_Type, (PyObject*)&Sock,
&key_file, &cert_file) )
return NULL;
rv = newSSLObject(Sock, key_file, cert_file);
if ( rv == NULL )
return NULL;
return (PyObject *)rv;
}
static char ssl_doc[] =
"ssl(socket, keyfile, certfile) -> sslobject";
static PyObject *
BUILD_FUNC_DEF_2(SSL_server, SSLObject *, self, PyObject *, args)
{
return PyString_FromString(self->server);
}
static PyObject *
BUILD_FUNC_DEF_2(SSL_issuer, SSLObject *, self, PyObject *, args)
{
return PyString_FromString(self->issuer);
}
/* SSL object methods */
static PyMethodDef SSLMethods[] = {
{ "write", (PyCFunction)SSL_SSLwrite, 1 },
{ "read", (PyCFunction)SSL_SSLread, 1 },
{ "server", (PyCFunction)SSL_server, 1 },
{ "issuer", (PyCFunction)SSL_issuer, 1 },
{ NULL, NULL}
};
static void SSL_dealloc(SSLObject *self)
{
if (self->server_cert) /* Possible not to have one? */
X509_free (self->server_cert);
SSL_CTX_free(self->ctx);
SSL_free(self->ssl);
Py_XDECREF(self->x_attr);
Py_XDECREF(self->Socket);
PyMem_DEL(self);
}
static PyObject *SSL_getattr(SSLObject *self, char *name)
{
return Py_FindMethod(SSLMethods, (PyObject *)self, name);
}
staticforward PyTypeObject SSL_Type = {
PyObject_HEAD_INIT(&PyType_Type)
0, /*ob_size*/
"SSL", /*tp_name*/
sizeof(SSLObject), /*tp_basicsize*/
0, /*tp_itemsize*/
/* methods */
(destructor)SSL_dealloc, /*tp_dealloc*/
0, /*tp_print*/
(getattrfunc)SSL_getattr, /*tp_getattr*/
0, /*tp_setattr*/
0, /*tp_compare*/
0, /*tp_repr*/
0, /*tp_as_number*/
0, /*tp_as_sequence*/
0, /*tp_as_mapping*/
0, /*tp_hash*/
};
static PyObject *SSL_SSLwrite(SSLObject *self, PyObject *args)
{
char *data;
int len = 0;
if (!PyArg_ParseTuple(args, "s|i", &data, &len))
return NULL;
if (!len)
len = strlen(data);
len = SSL_write(self->ssl, data, len);
return PyInt_FromLong((long)len);
}
static PyObject *SSL_SSLread(SSLObject *self, PyObject *args)
{
PyObject *buf;
int count = 0;
int len = 1024;
int res;
PyArg_ParseTuple(args, "|i", &len);
if (!(buf = PyString_FromStringAndSize((char *) 0, len)))
return NULL; /* Error object should already be set */
count = SSL_read(self->ssl, PyString_AsString(buf), len);
res = SSL_get_error(self->ssl, count);
switch (res) {
case 0: /* Good return value! */
break;
case 6:
PyErr_SetString(SSLErrorObject, "EOF");
Py_DECREF(buf);
return NULL;
break;
case 5:
default:
return PyErr_SetFromErrno(SSLErrorObject);
break;
}
fflush(stderr);
if (count < 0) {
Py_DECREF(buf);
return PyErr_SetFromErrno(SSLErrorObject);
}
if (count != len && _PyString_Resize(&buf, count) < 0)
return NULL;
return buf;
}
#endif /* USE_SSL */
/* List of functions exported by this module. */ /* List of functions exported by this module. */
static PyMethodDef PySocket_methods[] = { static PyMethodDef PySocket_methods[] = {
@ -1893,6 +2167,9 @@ static PyMethodDef PySocket_methods[] = {
{"htonl", PySocket_htonl, 0, htonl_doc}, {"htonl", PySocket_htonl, 0, htonl_doc},
{"inet_aton", PySocket_inet_aton, 0, inet_aton_doc}, {"inet_aton", PySocket_inet_aton, 0, inet_aton_doc},
{"inet_ntoa", PySocket_inet_ntoa, 0, inet_ntoa_doc}, {"inet_ntoa", PySocket_inet_ntoa, 0, inet_ntoa_doc},
#ifdef USE_SSL
{"ssl", PySocket_ssl, 1, ssl_doc},
#endif /* USE_SSL */
{NULL, NULL} /* Sentinel */ {NULL, NULL} /* Sentinel */
}; };
@ -1981,7 +2258,6 @@ OS2init()
#endif /* PYOS_OS2 */ #endif /* PYOS_OS2 */
/* Initialize this module. /* Initialize this module.
* This is called when the first 'import socket' is done, * This is called when the first 'import socket' is done,
* via a table in config.c, if config.c is compiled with USE_SOCKET * via a table in config.c, if config.c is compiled with USE_SOCKET
@ -2019,6 +2295,7 @@ ntohs(), ntohl() -- convert 16, 32 bit int from network to host byte order\n\
htons(), htonl() -- convert 16, 32 bit int from host to network byte order\n\ htons(), htonl() -- convert 16, 32 bit int from host to network byte order\n\
inet_aton() -- convert IP addr string (123.45.67.89) to 32-bit packed format\n\ inet_aton() -- convert IP addr string (123.45.67.89) to 32-bit packed format\n\
inet_ntoa() -- convert 32-bit packed format IP to string (123.45.67.89)\n\ inet_ntoa() -- convert 32-bit packed format IP to string (123.45.67.89)\n\
ssl() -- secure socket layer support (only available if configured)\n\
\n\ \n\
(*) not available on all platforms!)\n\ (*) not available on all platforms!)\n\
\n\ \n\
@ -2092,6 +2369,18 @@ initsocket()
PySocket_Error = PyErr_NewException("socket.error", NULL, NULL); PySocket_Error = PyErr_NewException("socket.error", NULL, NULL);
if (PySocket_Error == NULL) if (PySocket_Error == NULL)
return; return;
#ifdef USE_SSL
SSL_load_error_strings();
SSLeay_add_ssl_algorithms();
SSLErrorObject = PyErr_NewException("socket.sslerror", NULL, NULL);
if (SSLErrorObject == NULL)
return;
PyDict_SetItemString(d, "sslerror", SSLErrorObject);
Py_INCREF(&SSL_Type);
if (PyDict_SetItemString(d, "SSLType",
(PyObject *)&SSL_Type) != 0)
return;
#endif /* USE_SSL */
PyDict_SetItemString(d, "error", PySocket_Error); PyDict_SetItemString(d, "error", PySocket_Error);
PySocketSock_Type.ob_type = &PyType_Type; PySocketSock_Type.ob_type = &PyType_Type;
PySocketSock_Type.tp_doc = sockettype_doc; PySocketSock_Type.tp_doc = sockettype_doc;