//***************************************************************************** // // pysocket.c // // Contains a python socket module, and an Socket class that is a python // wrapper for NakedMud sockets. // //***************************************************************************** #include "../mud.h" #include "../utils.h" #include "../socket.h" #include "../character.h" #include "scripts.h" #include "pyplugs.h" #include "pyauxiliary.h" #include "pysocket.h" //***************************************************************************** // local structures and defines //***************************************************************************** // a list of the get/setters on the Exit class LIST *pysocket_getsetters = NULL; // a list of the methods on the Exit class LIST *pysocket_methods = NULL; typedef struct { PyObject_HEAD int uid; } PySocket; //***************************************************************************** // allocation, deallocation, initialization, and comparison //***************************************************************************** void PySocket_dealloc(PySocket *self) { self->ob_type->tp_free((PyObject*)self); } PyObject *PySocket_new(PyTypeObject *type, PyObject *args, PyObject *kwds) { PySocket *self; self = (PySocket *)type->tp_alloc(type, 0); self->uid = NOTHING; return (PyObject *)self; } int PySocket_init(PySocket *self, PyObject *args, PyObject *kwds) { char *kwlist[] = {"uid", NULL}; int uid = NOTHING; // get the uid if (!PyArg_ParseTupleAndKeywords(args, kwds, "i", kwlist, &uid)) { PyErr_Format(PyExc_TypeError, "Sockets may only be created using an uid"); return -1; } // make sure an socket with this name exists if(!propertyTableGet(sock_table, uid)) { PyErr_Format(PyExc_TypeError, "Socket with uid, %d, does not exist", uid); return -1; } self->uid = uid; return 0; } int PySocket_compare(PySocket *sock1, PySocket *sock2) { if(sock1->uid == sock2->uid) return 0; else if(sock1->uid < sock2->uid) return -1; else return 1; } //***************************************************************************** // getters and setters for the Socket class //***************************************************************************** PyObject *PySocket_getuid(PySocket *self, void *closure) { SOCKET_DATA *sock = PySocket_AsSocket((PyObject *)self); if(sock != NULL) return Py_BuildValue("i", socketGetUID(sock)); else return NULL; } PyObject *PySocket_getaccount(PySocket *self, void *closure) { SOCKET_DATA *sock = PySocket_AsSocket((PyObject *)self); if(sock == NULL) return NULL; else { ACCOUNT_DATA *acc = socketGetAccount(sock); if(acc == NULL) return Py_BuildValue("O", Py_None); return Py_BuildValue("O", accountGetPyFormBorrowed(acc)); } } PyObject *PySocket_getchar(PySocket *self, void *closure) { SOCKET_DATA *sock = PySocket_AsSocket((PyObject *)self); if(sock == NULL) return NULL; else { CHAR_DATA *ch = socketGetChar(sock); // for the time being, we don't return characters without UIDs... like ones // that are being created. We have to redo character generation to allow // for characters-in-progress to be referenced if(ch == NULL || charGetUID(ch) == NOBODY) return Py_BuildValue("O", Py_None); return Py_BuildValue("O", charGetPyFormBorrowed(ch)); } } PyObject *PySocket_get_outbound_text(PySocket *self, void *closure) { SOCKET_DATA *sock = PySocket_AsSocket((PyObject *)self); if(sock == NULL) return NULL; else { return Py_BuildValue("s", bufferString(socketGetOutbound(sock))); } } int PySocket_set_outbound_text(PySocket *self, PyObject *value, void *closure) { if(!PyString_Check(value)) { PyErr_Format(PyExc_TypeError, "Outbound text must be in string format."); return -1; } SOCKET_DATA *sock = PySocket_AsSocket((PyObject *)self); if(sock == NULL) return -1; else { bufferClear(socketGetOutbound(sock)); bufferCat(socketGetOutbound(sock), PyString_AsString(value)); return 0; } } PyObject *PySocket_get_can_use(PySocket *self, void *closure) { SOCKET_DATA *sock = PySocket_AsSocket((PyObject *)self); if(sock == NULL) return NULL; else return Py_BuildValue("i", (socketGetDNSLookupStatus(sock) == TSTATE_DONE ? TRUE : FALSE)); } PyObject *PySocket_bust_prompt(PySocket *self, PyObject *closure) { SOCKET_DATA *sock = PySocket_AsSocket((PyObject *)self); if(sock == NULL) { PyErr_Format(PyExc_StandardError, "Tried to bust prompt on nonexistent " "socket, %d.", PySocket_AsUid((PyObject *)self)); return NULL; } socketBustPrompt(sock); return Py_BuildValue("i", 1); } PyObject *PySocket_push_ih(PySocket *self, PyObject *args) { SOCKET_DATA *sock = PySocket_AsSocket((PyObject *)self); PyObject *handler = NULL; PyObject *prompt = NULL; if(sock == NULL) return NULL; if (!PyArg_ParseTuple(args, "OO", &handler, &prompt)) { PyErr_Format(PyExc_TypeError, "handler and prompt function must " "be supplied."); return NULL; } socketPushPyInputHandler(sock, handler, prompt); return Py_BuildValue("i", 1); } PyObject *PySocket_pop_ih(PySocket *self) { SOCKET_DATA *sock = PySocket_AsSocket((PyObject *)self); if(sock == NULL) return NULL; socketPopInputHandler(sock); return Py_BuildValue("i", 1); } PyObject *PySocket_replace_ih(PySocket *self, PyObject *args) { PyObject *retval = PySocket_pop_ih(self); if(retval == NULL) return NULL; Py_DECREF(retval); retval = PySocket_push_ih(self, args); if(retval == NULL) return NULL; Py_DECREF(retval); return Py_BuildValue("i", 1); } PyObject *PySocket_send_raw(PySocket *self, PyObject *value) { char *mssg = NULL; if (!PyArg_ParseTuple(value, "s", &mssg)) { PyErr_Format(PyExc_TypeError, "Sockets may only be sent strings"); return NULL; } SOCKET_DATA *sock = PySocket_AsSocket((PyObject *)self); if(sock != NULL) { send_to_socket(sock, "%s", mssg); return Py_BuildValue("i", 1); } else { PyErr_Format(PyExc_TypeError, "Tried to send message to nonexistant socket, %d.", self->uid); return NULL; } } PyObject *PySocket_send(PySocket *self, PyObject *value) { PyObject *retval = PySocket_send_raw(self, value); if(retval == NULL) return NULL; SOCKET_DATA *sock = PySocket_AsSocket((PyObject *)self); send_to_socket(sock, "\r\n"); Py_DECREF(retval); return Py_BuildValue("i", 1); } PyObject *PySocket_close(PySocket *self) { SOCKET_DATA *sock = PySocket_AsSocket((PyObject *)self); if(sock == NULL) return NULL; close_socket(sock, FALSE); return Py_BuildValue("i", 1); } //***************************************************************************** // methods for the Socket class //***************************************************************************** // // returns the specified piece of auxiliary data from the socket // if it is a piece of python auxiliary data. PyObject *PySocket_get_auxiliary(PySocket *self, PyObject *args) { char *keyword = NULL; if(!PyArg_ParseTuple(args, "s", &keyword)) { PyErr_Format(PyExc_TypeError, "getAuxiliary() must be supplied with the name that the " "auxiliary data was installed under!"); return NULL; } // make sure we exist SOCKET_DATA *sock = PySocket_AsSocket((PyObject *)self); if(sock == NULL) { PyErr_Format(PyExc_StandardError, "Tried to get auxiliary data for a nonexistant socket."); return NULL; } // make sure the auxiliary data exists if(!pyAuxiliaryDataExists(keyword)) { PyErr_Format(PyExc_StandardError, "No auxiliary data named '%s' exists!", keyword); return NULL; } PyObject *data = socketGetAuxiliaryData(sock, keyword); if(data == NULL) data = Py_None; PyObject *retval = Py_BuildValue("O", data); // Py_DECREF(data); return retval; } //***************************************************************************** // structures to define our methods and classes //***************************************************************************** PyTypeObject PySocket_Type = { PyObject_HEAD_INIT(NULL) 0, /*ob_size*/ "mudsock.Mudsock", /*tp_name*/ sizeof(PySocket), /*tp_basicsize*/ 0, /*tp_itemsize*/ (destructor)PySocket_dealloc,/*tp_dealloc*/ 0, /*tp_print*/ 0, /*tp_getattr*/ 0, /*tp_setattr*/ (cmpfunc)PySocket_compare, /*tp_compare*/ 0, /*tp_repr*/ 0, /*tp_as_number*/ 0, /*tp_as_sequence*/ 0, /*tp_as_mapping*/ 0, /*tp_hash */ 0, /*tp_call*/ 0, /*tp_str*/ 0, /*tp_getattro*/ 0, /*tp_setattro*/ 0, /*tp_as_buffer*/ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /*tp_flags*/ "Python Socket object", /* tp_doc */ 0, /* tp_traverse */ 0, /* tp_clear */ 0, /* tp_richcompare */ 0, /* tp_weaklistoffset */ 0, /* tp_iter */ 0, /* tp_iternext */ 0, /* tp_methods */ 0, /* tp_members */ 0, /* tp_getset */ 0, /* tp_base */ 0, /* tp_dict */ 0, /* tp_descr_get */ 0, /* tp_descr_set */ 0, /* tp_dictoffset */ (initproc)PySocket_init, /* tp_init */ 0, /* tp_alloc */ PySocket_new, /* tp_new */ }; //***************************************************************************** // methods in the mudsock module //***************************************************************************** PyObject *PySocket_all_sockets(PyObject *self) { PyObject *list = PyList_New(0); LIST_ITERATOR *sock_i = newListIterator(socket_list); SOCKET_DATA *sock = NULL; ITERATE_LIST(sock, sock_i) { PyList_Append(list, socketGetPyFormBorrowed(sock)); } deleteListIterator(sock_i); PyObject *retval = Py_BuildValue("O", list); Py_DECREF(list); return retval; } PyMethodDef socket_module_methods[] = { { "socket_list", (PyCFunction)PySocket_all_sockets, METH_NOARGS, "Returns a list of all sockets currently connected." }, {NULL, NULL, 0, NULL} /* Sentinel */ }; //***************************************************************************** // implementation of pyexit.h //***************************************************************************** void PySocket_addGetSetter(const char *name, void *g, void *s,const char *doc){ // make sure our list of get/setters is created if(pysocket_getsetters == NULL) pysocket_getsetters = newList(); // make the GetSetter def PyGetSetDef *def = calloc(1, sizeof(PyGetSetDef)); def->name = strdup(name); def->get = (getter)g; def->set = (setter)s; def->doc = (doc ? strdup(doc) : NULL); def->closure = NULL; listPut(pysocket_getsetters, def); } void PySocket_addMethod(const char *name, void *f, int flags, const char *doc){ // make sure our list of methods is created if(pysocket_methods == NULL) pysocket_methods = newList(); // make the Method def PyMethodDef *def = calloc(1, sizeof(PyMethodDef)); def->ml_name = strdup(name); def->ml_meth = (PyCFunction)f; def->ml_flags = flags; def->ml_doc = (doc ? strdup(doc) : NULL); listPut(pysocket_methods, def); } // initialize sockets for use. This must be called AFTER PyMODINIT_FUNC init_PySocket(void) { PyObject* module = NULL; // add all of the basic getsetters PySocket_addGetSetter("uid", PySocket_getuid, NULL, "the socket's uid."); PySocket_addGetSetter("account", PySocket_getaccount, NULL, "the socket's account."); PySocket_addGetSetter("character", PySocket_getchar, NULL, "the socket's character."); PySocket_addGetSetter("char", PySocket_getchar, NULL, "the socket's character."); PySocket_addGetSetter("ch", PySocket_getchar, NULL, "the socket's character."); PySocket_addGetSetter("outbound_text", PySocket_get_outbound_text,PySocket_set_outbound_text, "the socket's outbound text."); PySocket_addGetSetter("can_use", PySocket_get_can_use, NULL, "Returns whether or not the socket is ready for use. " "Sockets become available after their dns resolves."); // add all of the basic methods PySocket_addMethod("getAuxiliary", PySocket_get_auxiliary, METH_VARARGS, "gets the socket auxiliary data with given key."); PySocket_addMethod("send", PySocket_send, METH_VARARGS, "sends text to the socket with appended newline."); PySocket_addMethod("send_raw", PySocket_send_raw, METH_VARARGS, "sends text to the socket."); PySocket_addMethod("pop_ih", PySocket_pop_ih, METH_NOARGS, "Pops the socket's current input handler."); PySocket_addMethod("push_ih", PySocket_push_ih, METH_VARARGS, "pushes on a new input handler."); PySocket_addMethod("replace_ih", PySocket_replace_ih, METH_VARARGS, "replaces the socket's input handler."); PySocket_addMethod("close", PySocket_close, METH_VARARGS, "closes the socket."); PySocket_addMethod("bust_prompt", PySocket_bust_prompt, METH_NOARGS, "busts the socket's prompt so it will be displayed."); // add in all the getsetters and methods makePyType(&PySocket_Type, pysocket_getsetters, pysocket_methods); deleteListWith(pysocket_getsetters, free); pysocket_getsetters = NULL; deleteListWith(pysocket_methods, free); pysocket_methods = NULL; // make sure the socket class is ready to be made if (PyType_Ready(&PySocket_Type) < 0) return; // initialize the module module = Py_InitModule3("mudsock", socket_module_methods, "The socket module, for all MUD socket-related " "stuff."); // make sure the module parsed OK if (module == NULL) return; // add the Socket class to the socket module PyTypeObject *type = &PySocket_Type; PyModule_AddObject(module, "Mudsock", (PyObject *)type); Py_INCREF(&PySocket_Type); } int PySocket_Check(PyObject *value) { return PyObject_TypeCheck(value, &PySocket_Type); } int PySocket_AsUid(PyObject *sock) { return ((PySocket *)sock)->uid; } SOCKET_DATA *PySocket_AsSocket(PyObject *ch) { return propertyTableGet(sock_table, PySocket_AsUid(ch)); } PyObject * newPySocket(SOCKET_DATA *sock) { PySocket *pysock = (PySocket *)PySocket_new(&PySocket_Type, NULL, NULL); pysock->uid = socketGetUID(sock); return (PyObject *)pysock; }