[Python-checkins] CVS: python/dist/src/Modules socketmodule.c,1.173,1.174

Jeremy Hylton jhylton@users.sourceforge.net
Wed, 10 Oct 2001 16:55:46 -0700


Update of /cvsroot/python/python/dist/src/Modules
In directory usw-pr-cvs1:/tmp/cvs-serv24881

Modified Files:
	socketmodule.c 
Log Message:
Lots of code reorganization with a few small API changes.

Change all the local names that start with SSL to start with PySSL.
The OpenSSL library defines lots of calls that start with "SSL_".  The
calls for Python's SSL objects also started with "SSL_".  This choice
made it really confusing to figure out which calls were to the library
and which calls were local to the file.

Add PySSL_SetError() that sets an exception based on the information
from SSL_get_error().  This function will eventually replace all the
calls that set it with an error message that is based on the name of
the call that failed rather than the reason it failed.  (Example: If
SSL_connect() failed it used to report "SSL_connect error" now it will
offer a specific message about why SSL_connect failed.)

    XXX It might be helpful to augment the error message generated
    below with the name of the SSL function that generated the error.
    I expect it's obvious most of the time.

Remove several unnecessary INCREFs in the module's constructor call.
PyDict_SetItem() and friends do the INCREF for you.





Index: socketmodule.c
===================================================================
RCS file: /cvsroot/python/python/dist/src/Modules/socketmodule.c,v
retrieving revision 1.173
retrieving revision 1.174
diff -C2 -d -r1.173 -r1.174
*** socketmodule.c	2001/10/10 22:37:48	1.173
--- socketmodule.c	2001/10/10 23:55:43	1.174
***************
*** 283,287 ****
  
  #ifdef USE_SSL
! static PyObject *SSLErrorObject;
  #endif /* USE_SSL */
  
--- 283,287 ----
  
  #ifdef USE_SSL
! static PyObject *PySSLErrorObject;
  #endif /* USE_SSL */
  
***************
*** 499,509 ****
  	char		issuer[256];
  
! } SSLObject;
  
! staticforward PyTypeObject SSL_Type;
! 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 */
--- 499,509 ----
  	char		issuer[256];
  
! } PySSLObject;
  
! staticforward PyTypeObject PySSL_Type;
! staticforward PyObject *PySSL_SSLwrite(PySSLObject *self, PyObject *args);
! staticforward PyObject *PySSL_SSLread(PySSLObject *self, PyObject *args);
  
! #define PySSLObject_Check(v)	((v)->ob_type == &PySSL_Type)
  
  #endif /* USE_SSL */
***************
*** 2491,2507 ****
  Get host and port for a sockaddr.";
  
  
  #ifdef USE_SSL
  
  /* This is a C function to be called for new object initialization */
! static SSLObject *
! newSSLObject(PySocketSockObject *Sock, char *key_file, char *cert_file)
  {
! 	SSLObject *self;
  	char *errstr = NULL;
  
! 	self = PyObject_New(SSLObject, &SSL_Type); /* Create new object */
  	if (self == NULL){
! 		errstr = "newSSLObject error";
  		goto fail;
  	}
--- 2491,2576 ----
  Get host and port for a sockaddr.";
  
+ /* XXX It might be helpful to augment the error message generated
+    below with the name of the SSL function that generated the error.
+    I expect it's obvious most of the time.
+ */
  
  #ifdef USE_SSL
+ static PyObject *
+ PySSL_SetError(SSL *ssl, int ret)
+ {
+ 	PyObject *v, *n, *s;
+ 	char *errstr;
+ 	int err;
+ 
+ 	assert(ret <= 0);
+     
+ 	err = SSL_get_error(ssl, ret);
+ 	n = PyInt_FromLong(err);
+ 	if (n == NULL)
+ 		return NULL;
+ 	v = PyTuple_New(2);
+ 	if (v == NULL) {
+ 		Py_DECREF(n);
+ 		return NULL;
+ 	}
+ 
+ 	switch (SSL_get_error(ssl, ret)) {
+ 	case SSL_ERROR_ZERO_RETURN:
+ 		errstr = "TLS/SSL connection has been closed";
+ 		break;
+ 	case SSL_ERROR_WANT_READ:
+ 		errstr = "The operation did not complete (read)";
+ 		break;
+ 	case SSL_ERROR_WANT_WRITE:
+ 		errstr = "The operation did not complete (write)";
+ 		break;
+ 	case SSL_ERROR_WANT_X509_LOOKUP:
+ 		errstr = "The operation did not complete (X509 lookup)";
+ 		break;
+ 	case SSL_ERROR_SYSCALL:
+ 	case SSL_ERROR_SSL:
+ 	{
+ 		unsigned long e = ERR_get_error();
+ 		if (e == 0) {
+ 			/* an EOF was observed that violates the protocol */
+ 			errstr = "EOF occurred in violation of protocol";
+ 		} else if (e == -1) {
+ 			/* the underlying BIO reported an I/O error */
+ 			Py_DECREF(v);
+ 			Py_DECREF(n);
+ 			PyErr_SetFromErrno(PyExc_IOError);
+ 			return NULL;
+ 		} else {
+ 			/* XXX Protected by global interpreter lock */
+ 			errstr = ERR_error_string(e, NULL);
+ 		}
+ 		break;
+ 	}
+ 	default:
+ 		errstr = "Invalid error code";
+ 	}
+ 	s = PyString_FromString(errstr);
+ 	if (s == NULL) {
+ 		Py_DECREF(v);
+ 		Py_DECREF(n);
+ 	}
+ 	PyTuple_SET_ITEM(v, 0, n);
+ 	PyTuple_SET_ITEM(v, 1, s);
+ 	PyErr_SetObject(PySSLErrorObject, v);
+ 	return NULL;
+ }
  
  /* This is a C function to be called for new object initialization */
! static PySSLObject *
! newPySSLObject(PySocketSockObject *Sock, char *key_file, char *cert_file)
  {
! 	PySSLObject *self;
  	char *errstr = NULL;
+ 	int ret;
  
! 	self = PyObject_New(PySSLObject, &PySSL_Type); /* Create new object */
  	if (self == NULL){
! 		errstr = "newPySSLObject error";
  		goto fail;
  	}
***************
*** 2524,2528 ****
  	}
  
! 	if (key_file && cert_file) {
  		if (SSL_CTX_use_PrivateKey_file(self->ctx, key_file,
  						SSL_FILETYPE_PEM) < 1) {
--- 2593,2597 ----
  	}
  
! 	if (key_file) {
  		if (SSL_CTX_use_PrivateKey_file(self->ctx, key_file,
  						SSL_FILETYPE_PEM) < 1) {
***************
*** 2546,2551 ****
  	/* Actually negotiate SSL connection */
  	/* XXX If SSL_connect() returns 0, it's also a failure. */
! 	if ((SSL_connect(self->ssl)) == -1) {
! 		errstr = "SSL_connect error";
  		goto fail;
  	}
--- 2615,2621 ----
  	/* Actually negotiate SSL connection */
  	/* XXX If SSL_connect() returns 0, it's also a failure. */
! 	ret = SSL_connect(self->ssl);
! 	if (ret <= 0) {
! 		PySSL_SetError(self->ssl, ret);
  		goto fail;
  	}
***************
*** 2563,2567 ****
   fail:
  	if (errstr)
! 		PyErr_SetString(SSLErrorObject, errstr);
  	Py_DECREF(self);
  	return NULL;
--- 2633,2637 ----
   fail:
  	if (errstr)
! 		PyErr_SetString(PySSLErrorObject, errstr);
  	Py_DECREF(self);
  	return NULL;
***************
*** 2572,2586 ****
  PySocket_ssl(PyObject *self, PyObject *args)
  {
! 	SSLObject *rv;
  	PySocketSockObject *Sock;
! 	char *key_file;
! 	char *cert_file;
  
! 	if (!PyArg_ParseTuple(args, "O!zz:ssl",
  			      &PySocketSock_Type, (PyObject*)&Sock,
  			      &key_file, &cert_file))
  		return NULL;
  
! 	rv = newSSLObject(Sock, key_file, cert_file);
  	if (rv == NULL)
  		return NULL;
--- 2642,2656 ----
  PySocket_ssl(PyObject *self, PyObject *args)
  {
! 	PySSLObject *rv;
  	PySocketSockObject *Sock;
! 	char *key_file = NULL;
! 	char *cert_file = NULL;
  
! 	if (!PyArg_ParseTuple(args, "O!|zz:ssl",
  			      &PySocketSock_Type, (PyObject*)&Sock,
  			      &key_file, &cert_file))
  		return NULL;
  
! 	rv = newPySSLObject(Sock, key_file, cert_file);
  	if (rv == NULL)
  		return NULL;
***************
*** 2592,2596 ****
  
  static PyObject *
! SSL_server(SSLObject *self, PyObject *args)
  {
  	return PyString_FromString(self->server);
--- 2662,2666 ----
  
  static PyObject *
! PySSL_server(PySSLObject *self, PyObject *args)
  {
  	return PyString_FromString(self->server);
***************
*** 2598,2602 ****
  
  static PyObject *
! SSL_issuer(SSLObject *self, PyObject *args)
  {
  	return PyString_FromString(self->issuer);
--- 2668,2672 ----
  
  static PyObject *
! PySSL_issuer(PySSLObject *self, PyObject *args)
  {
  	return PyString_FromString(self->issuer);
***************
*** 2606,2618 ****
  /* 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? */
--- 2676,2688 ----
  /* SSL object methods */
  
! static PyMethodDef PySSLMethods[] = {
! 	{"write", (PyCFunction)PySSL_SSLwrite, 1},
! 	{"read", (PyCFunction)PySSL_SSLread, 1},
! 	{"server", (PyCFunction)PySSL_server, 1},
! 	{"issuer", (PyCFunction)PySSL_issuer, 1},
  	{NULL, NULL}
  };
  
! static void PySSL_dealloc(PySSLObject *self)
  {
  	if (self->server_cert)	/* Possible not to have one? */
***************
*** 2626,2644 ****
  }
  
! static PyObject *SSL_getattr(SSLObject *self, char *name)
  {
! 	return Py_FindMethod(SSLMethods, (PyObject *)self, name);
  }
  
! staticforward PyTypeObject SSL_Type = {
  	PyObject_HEAD_INIT(NULL)
  	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*/
--- 2696,2714 ----
  }
  
! static PyObject *PySSL_getattr(PySSLObject *self, char *name)
  {
! 	return Py_FindMethod(PySSLMethods, (PyObject *)self, name);
  }
  
! staticforward PyTypeObject PySSL_Type = {
  	PyObject_HEAD_INIT(NULL)
  	0,				/*ob_size*/
  	"SSL",			/*tp_name*/
! 	sizeof(PySSLObject),		/*tp_basicsize*/
  	0,				/*tp_itemsize*/
  	/* methods */
! 	(destructor)PySSL_dealloc,	/*tp_dealloc*/
  	0,				/*tp_print*/
! 	(getattrfunc)PySSL_getattr,	/*tp_getattr*/
  	0,				/*tp_setattr*/
  	0,				/*tp_compare*/
***************
*** 2652,2656 ****
  
  
! static PyObject *SSL_SSLwrite(SSLObject *self, PyObject *args)
  {
  	char *data;
--- 2722,2726 ----
  
  
! static PyObject *PySSL_SSLwrite(PySSLObject *self, PyObject *args)
  {
  	char *data;
***************
*** 2664,2668 ****
  }
  
! static PyObject *SSL_SSLread(SSLObject *self, PyObject *args)
  {
  	PyObject *buf;
--- 2734,2738 ----
  }
  
! static PyObject *PySSL_SSLread(PySSLObject *self, PyObject *args)
  {
  	PyObject *buf;
***************
*** 2687,2691 ****
  		break;
  	default:
! 		return PyErr_SetFromErrno(SSLErrorObject);
  	}
  
--- 2757,2761 ----
  		break;
  	default:
! 		return PyErr_SetFromErrno(PySSLErrorObject);
  	}
  
***************
*** 2694,2698 ****
  	if (count < 0) {
  		Py_DECREF(buf);
! 		return PyErr_SetFromErrno(SSLErrorObject);
  	}
  
--- 2764,2768 ----
  	if (count < 0) {
  		Py_DECREF(buf);
! 		return PyErr_SetFromErrno(PySSLErrorObject);
  	}
  
***************
*** 2905,2909 ****
  #endif /* RISCOS */
  #ifdef USE_SSL
! 	SSL_Type.ob_type = &PyType_Type;
  #endif
  	m = Py_InitModule3("_socket", PySocket_methods, module_doc);
--- 2975,2979 ----
  #endif /* RISCOS */
  #ifdef USE_SSL
! 	PySSL_Type.ob_type = &PyType_Type;
  #endif
  	m = Py_InitModule3("_socket", PySocket_methods, module_doc);
***************
*** 2925,2940 ****
  	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 */
  	PySocketSock_Type.ob_type = &PyType_Type;
  	PySocketSock_Type.tp_doc = sockettype_doc;
- 	Py_INCREF(&PySocketSock_Type);
  	if (PyDict_SetItemString(d, "SocketType",
  				 (PyObject *)&PySocketSock_Type) != 0)
--- 2995,3008 ----
  	SSL_load_error_strings();
  	SSLeay_add_ssl_algorithms();
! 	PySSLErrorObject = PyErr_NewException("socket.sslerror", NULL, NULL);
! 	if (PySSLErrorObject == NULL)
  		return;
! 	PyDict_SetItemString(d, "sslerror", PySSLErrorObject);
  	if (PyDict_SetItemString(d, "SSLType",
! 				 (PyObject *)&PySSL_Type) != 0)
  		return;
  #endif /* USE_SSL */
  	PySocketSock_Type.ob_type = &PyType_Type;
  	PySocketSock_Type.tp_doc = sockettype_doc;
  	if (PyDict_SetItemString(d, "SocketType",
  				 (PyObject *)&PySocketSock_Type) != 0)