The InspIRCd Project
Home | Developers | Wiki | Forums | Bug Tracker | SVN | Download
Main Page | Namespace List | Class Hierarchy | Alphabetical List | Class List | Directories | File List | Namespace Members | Class Members | File Members

m_xmlsocket.cpp

Go to the documentation of this file.
00001 /*       +------------------------------------+
00002  *       | Inspire Internet Relay Chat Daemon |
00003  *       +------------------------------------+
00004  *
00005  *  InspIRCd: (C) 2002-2008 InspIRCd Development Team
00006  * See: http://www.inspircd.org/wiki/index.php/Credits
00007  *
00008  * This program is free but copyrighted software; see
00009  *            the file COPYING for details.
00010  *
00011  * ---------------------------------------------------
00012  */
00013 
00014 #include "inspircd.h"
00015 
00016 /* $ModDesc: Provides XMLSocket support for clients */
00017 
00018 class ModuleXMLSocket : public Module
00019 {
00020         ConfigReader* Conf;
00021         std::vector<std::string> listenports;
00022 
00023  public:
00024 
00025         ModuleXMLSocket(InspIRCd* Me)
00026                 : Module(Me)
00027         {
00028                 OnRehash(NULL,"");
00029                 Implementation eventlist[] = { I_OnUnloadModule, I_OnRawSocketRead, I_OnRawSocketWrite, I_OnRehash, I_OnHookUserIO, I_OnCleanup };
00030                 ServerInstance->Modules->Attach(eventlist, this, 6);
00031         }
00032 
00033         bool isin(const std::string &host, int port, const std::vector<std::string> &portlist)
00034         {
00035                 if (std::find(portlist.begin(), portlist.end(), "*:" + ConvToStr(port)) != portlist.end())
00036                         return true;
00037 
00038                 if (std::find(portlist.begin(), portlist.end(), ":" + ConvToStr(port)) != portlist.end())
00039                         return true;
00040 
00041                 return std::find(portlist.begin(), portlist.end(), host + ":" + ConvToStr(port)) != portlist.end();
00042         }
00043 
00044         virtual void OnRehash(User* user, const std::string &param)
00045         {
00046 
00047                 Conf = new ConfigReader(ServerInstance);
00048 
00049                 listenports.clear();
00050 
00051                 for (int i = 0; i < Conf->Enumerate("bind"); i++)
00052                 {
00053                         // For each <bind> tag
00054                         std::string x = Conf->ReadValue("bind", "type", i);
00055                         if (((x.empty()) || (x == "clients")) && (Conf->ReadFlag("bind", "xmlsocket", i)))
00056                         {
00057                                 // Get the port we're meant to be listening on with SSL
00058                                 std::string port = Conf->ReadValue("bind", "port", i);
00059                                 std::string addr = Conf->ReadValue("bind", "address", i);
00060 
00061                                 irc::portparser portrange(port, false);
00062                                 long portno = -1;
00063                                 while ((portno = portrange.GetToken()))
00064                                 {
00065                                         try
00066                                         {
00067                                                 listenports.push_back(addr + ":" + ConvToStr(portno));
00068                                                 for (size_t j = 0; j < ServerInstance->Config->ports.size(); j++)
00069                                                         if ((ServerInstance->Config->ports[j]->GetPort() == portno) && (ServerInstance->Config->ports[j]->GetIP() == addr))
00070                                                                 ServerInstance->Config->ports[j]->SetDescription("xml");
00071                                         }
00072                                         catch (ModuleException &e)
00073                                         {
00074                                                 ServerInstance->Logs->Log("m_xmlsocket",DEFAULT, "m_xmlsocket.so: FAILED to enable XMLSocket on port %ld: %s. Maybe you have another similar module loaded?", portno, e.GetReason());
00075                                         }
00076                                 }
00077                         }
00078                 }
00079 
00080                 delete Conf;
00081         }
00082 
00083         virtual ~ModuleXMLSocket()
00084         {
00085         }
00086 
00087         virtual void OnUnloadModule(Module* mod, const std::string &name)
00088         {
00089                 if (mod == this)
00090                 {
00091                         for(unsigned int i = 0; i < listenports.size(); i++)
00092                         {
00093                                 for (size_t j = 0; j < ServerInstance->Config->ports.size(); j++)
00094                                         if (listenports[i] == (ServerInstance->Config->ports[j]->GetIP()+":"+ConvToStr(ServerInstance->Config->ports[j]->GetPort())))
00095                                                 ServerInstance->Config->ports[j]->SetDescription("plaintext");
00096                         }
00097                 }
00098         }
00099 
00100         virtual void OnCleanup(int target_type, void* item)
00101         {
00102                 if(target_type == TYPE_USER)
00103                 {
00104                         User* user = (User*)item;
00105                         if(user->GetIOHook() == this)
00106                                 user->DelIOHook();
00107                 }
00108         }
00109 
00110         virtual Version GetVersion()
00111         {
00112                 return Version("$Id: m_xmlsocket.cpp 10457 2008-09-07 20:07:50Z w00t $", VF_VENDOR, API_VERSION);
00113         }
00114 
00115         virtual void OnHookUserIO(User* user, const std::string &targetip)
00116         {
00117                 if (!user->GetIOHook() && isin(targetip,user->GetPort(),listenports))
00118                 {
00119                         /* Hook the user with our module */
00120                         user->AddIOHook(this);
00121                 }
00122         }
00123 
00124         virtual int OnRawSocketRead(int fd, char* buffer, unsigned int count, int &readresult)
00125         {
00126                 User* user = dynamic_cast<User*>(ServerInstance->FindDescriptor(fd));
00127 
00128                 if (user == NULL)
00129                         return -1;
00130 
00131                 int result = user->ReadData(buffer, count);
00132 
00133                 if ((result == -1) && (errno == EAGAIN))
00134                         return -1;
00135                 else if (result < 1)
00136                         return 0;
00137 
00138                 /* XXX: The core is more than happy to split lines purely on an \n
00139                  * rather than a \r\n. This is good for us as it means that the size
00140                  * of data we are receiving is exactly the same as the size of data
00141                  * we asked for, and we dont need to re-implement our own socket
00142                  * buffering (See below)
00143                  */
00144                 for (int n = 0; n < result; n++)
00145                         if (buffer[n] == 0)
00146                                 buffer[n] = '\n';
00147 
00148                 readresult = result;
00149                 return result;
00150         }
00151 
00152         virtual int OnRawSocketWrite(int fd, const char* buffer, int count)
00153         {
00154                 User* user = dynamic_cast<User*>(ServerInstance->FindDescriptor(fd));
00155 
00156                 if (user == NULL)
00157                         return -1;
00158 
00159                 /* We want to alter the buffer, so we have to make a copy */
00160                 char * tmpbuffer = new char[count + 1];
00161                 memcpy(tmpbuffer, buffer, count);
00162 
00163                 /* XXX: This will actually generate lines "looking\0\0like\0\0this"
00164                  * rather than lines "looking\0like\0this". This shouldnt be a problem
00165                  * to the client, but it saves us a TON of processing and the need
00166                  * to re-implement socket buffering, as the data we are sending is
00167                  * exactly the same length as the data we are receiving.
00168                  */
00169                 for (int n = 0; n < count; n++)
00170                         if ((tmpbuffer[n] == '\r') || (tmpbuffer[n] == '\n'))
00171                                 tmpbuffer[n] = 0;
00172 
00173                 user->AddWriteBuf(std::string(tmpbuffer,count));
00174                 delete [] tmpbuffer;
00175 
00176                 return 1;
00177         }
00178 
00179 };
00180 
00181 MODULE_INIT(ModuleXMLSocket)
00182