/* Socket module header file */ /* Includes needed for the sockaddr_* symbols below */ #ifndef MS_WINDOWS #ifdef __VMS # include # else # include # endif # include # if !(defined(__BEOS__) || defined(__CYGWIN__) || (defined(PYOS_OS2) && defined(PYCC_VACPP))) # include # endif #else /* MS_WINDOWS */ #if _MSC_VER >= 1300 # include # include # define HAVE_ADDRINFO # define HAVE_SOCKADDR_STORAGE # define HAVE_GETADDRINFO # define HAVE_GETNAMEINFO # define ENABLE_IPV6 #else # include #endif #endif #ifdef HAVE_SYS_UN_H # include #else # undef AF_UNIX #endif #ifdef HAVE_BLUETOOTH_BLUETOOTH_H #include #include #include #include #endif #ifdef HAVE_BLUETOOTH_H #include #endif #ifdef HAVE_NETPACKET_PACKET_H # include # include # include #endif #ifndef Py__SOCKET_H #define Py__SOCKET_H #ifdef __cplusplus extern "C" { #endif /* Python module and C API name */ #define PySocket_MODULE_NAME "_socket" #define PySocket_CAPI_NAME "CAPI" /* Abstract the socket file descriptor type */ #ifdef MS_WINDOWS typedef SOCKET SOCKET_T; # ifdef MS_WIN64 # define SIZEOF_SOCKET_T 8 # else # define SIZEOF_SOCKET_T 4 # endif #else typedef int SOCKET_T; # define SIZEOF_SOCKET_T SIZEOF_INT #endif /* Socket address */ typedef union sock_addr { struct sockaddr_in in; #ifdef AF_UNIX struct sockaddr_un un; #endif #ifdef ENABLE_IPV6 struct sockaddr_in6 in6; struct sockaddr_storage storage; #endif #ifdef HAVE_BLUETOOTH_BLUETOOTH_H struct sockaddr_l2 bt_l2; struct sockaddr_rc bt_rc; struct sockaddr_sco bt_sco; #endif #ifdef HAVE_NETPACKET_PACKET_H struct sockaddr_ll ll; #endif } sock_addr_t; /* The object holding a socket. It holds some extra information, like the address family, which is used to decode socket address arguments properly. */ typedef struct { PyObject_HEAD SOCKET_T sock_fd; /* Socket file descriptor */ int sock_family; /* Address family, e.g., AF_INET */ int sock_type; /* Socket type, e.g., SOCK_STREAM */ int sock_proto; /* Protocol type, usually 0 */ sock_addr_t sock_addr; /* Socket address */ PyObject *(*errorhandler)(void); /* Error handler; checks errno, returns NULL and sets a Python exception */ double sock_timeout; /* Operation timeout in seconds; 0.0 means non-blocking */ } PySocketSockObject; /* --- C API ----------------------------------------------------*/ /* Short explanation of what this C API export mechanism does and how it works: The _ssl module needs access to the type object defined in the _socket module. Since cross-DLL linking introduces a lot of problems on many platforms, the "trick" is to wrap the C API of a module in a struct which then gets exported to other modules via a PyCObject. The code in socketmodule.c defines this struct (which currently only contains the type object reference, but could very well also include other C APIs needed by other modules) and exports it as PyCObject via the module dictionary under the name "CAPI". Other modules can now include the socketmodule.h file which defines the needed C APIs to import and set up a static copy of this struct in the importing module. After initialization, the importing module can then access the C APIs from the _socket module by simply referring to the static struct, e.g. Load _socket module and its C API; this sets up the global PySocketModule: if (PySocketModule_ImportModuleAndAPI()) return; Now use the C API as if it were defined in the using module: if (!PyArg_ParseTuple(args, "O!|zz:ssl", PySocketModule.Sock_Type, (PyObject*)&Sock, &key_file, &cert_file)) return NULL; Support could easily be extended to export more C APIs/symbols this way. Currently, only the type object is exported, other candidates would be socket constructors and socket access functions. */ /* C API for usage by other Python modules */ typedef struct { PyTypeObject *Sock_Type; PyObject *error; } PySocketModule_APIObject; /* XXX The net effect of the following appears to be to define a function XXX named PySocketModule_APIObject in _ssl.c. It's unclear why it isn't XXX defined there directly. >>> It's defined here because other modules might also want to use >>> the C API. */ #ifndef PySocket_BUILDING_SOCKET /* --- C API ----------------------------------------------------*/ /* Interfacestructure to C API for other modules. Call PySocketModule_ImportModuleAndAPI() to initialize this structure. After that usage is simple: if (!PyArg_ParseTuple(args, "O!|zz:ssl", &PySocketModule.Sock_Type, (PyObject*)&Sock, &key_file, &cert_file)) return NULL; ... */ static PySocketModule_APIObject PySocketModule; /* You *must* call this before using any of the functions in PySocketModule and check its outcome; otherwise all accesses will result in a segfault. Returns 0 on success. */ #ifndef DPRINTF # define DPRINTF if (0) printf #endif static int PySocketModule_ImportModuleAndAPI(void) { PyObject *mod = 0, *v = 0; char *apimodule = PySocket_MODULE_NAME; char *apiname = PySocket_CAPI_NAME; void *api; DPRINTF("Importing the %s C API...\n", apimodule); mod = PyImport_ImportModule(apimodule); if (mod == NULL) goto onError; DPRINTF(" %s package found\n", apimodule); v = PyObject_GetAttrString(mod, apiname); if (v == NULL) goto onError; Py_DECREF(mod); DPRINTF(" API object %s found\n", apiname); api = PyCObject_AsVoidPtr(v); if (api == NULL) goto onError; Py_DECREF(v); memcpy(&PySocketModule, api, sizeof(PySocketModule)); DPRINTF(" API object loaded and initialized.\n"); return 0; onError: DPRINTF(" not found.\n"); Py_XDECREF(mod); Py_XDECREF(v); return -1; } #endif /* !PySocket_BUILDING_SOCKET */ #ifdef __cplusplus } #endif #endif /* !Py__SOCKET_H */