File indexing completed on 2024-12-01 06:51:47
0001 /*************************************************************************** 0002 cunixsocket.cpp - UNIX domain socket 0003 ------------------- 0004 begin : Pi okt 3 2003 0005 copyright : (C) 2003-2009 by Tomas Mecir 0006 email : kmuddy@kmuddy.com 0007 ***************************************************************************/ 0008 0009 /*************************************************************************** 0010 * * 0011 * This program is free software; you can redistribute it and/or modify * 0012 * it under the terms of the GNU General Public License as published by * 0013 * the Free Software Foundation; either version 2 of the License, or * 0014 * (at your option) any later version. * 0015 * * 0016 ***************************************************************************/ 0017 0018 #include "cunixsocket.h" 0019 0020 #include <qsocketnotifier.h> 0021 0022 #include <fcntl.h> 0023 #include <stdio.h> 0024 #include <stdlib.h> 0025 #include <unistd.h> 0026 #include <sys/socket.h> 0027 #include <sys/types.h> 0028 0029 #include "cactionmanager.h" 0030 #include "crunninglist.h" 0031 #include "cvariablelist.h" 0032 0033 cUnixSocket::cUnixSocket (int _sess, cRunningScript *rs) : sess(_sess) 0034 { 0035 script = rs; 0036 0037 readnotifier = writenotifier = 0; 0038 readCache = writeCache = QString::null; 0039 id = -1; 0040 varlist = 0; 0041 connected = false; 0042 0043 //first of all, we need a file name 0044 char tmp_template[] = "/tmp/kmXXXXXX"; 0045 char *dirname = mkdtemp (tmp_template); 0046 if (dirname != 0) //only if it didn't fail 0047 { 0048 name = dirname; 0049 name += "/socket"; 0050 //now that we have the name, we create a socket and set some parameters 0051 id = socket (AF_UNIX, SOCK_STREAM, 0); 0052 sa.sun_family = AF_UNIX; 0053 strcpy (sa.sun_path, name.toLatin1()); 0054 fcntl (id, O_NONBLOCK); 0055 if (bind (id, (const sockaddr *) &sa, sizeof (sa)) == -1) 0056 { 0057 close (id); 0058 id = -1; 0059 unlink (name.toLatin1()); 0060 rmdir (dirname); 0061 return; 0062 } 0063 0064 //it's a listening connect... 0065 listen (id, 1); 0066 0067 //the notifier will tell us when the connection is here 0068 readnotifier = new QSocketNotifier (id, QSocketNotifier::Read, this); 0069 connect (readnotifier, SIGNAL (activated (int)), this, SLOT (readData (int))); 0070 0071 //finally, get a pointer to the list of variables 0072 varlist = dynamic_cast<cVariableList *>(cActionManager::self()->object ("variables", sess)); 0073 } 0074 } 0075 0076 cUnixSocket::~cUnixSocket () 0077 { 0078 //delete the notifiers 0079 readnotifier->setEnabled (false); 0080 delete readnotifier; 0081 delete writenotifier; 0082 0083 //close the socket 0084 close (id2); 0085 0086 //and remove its file 0087 unlink (name.toLatin1()); 0088 rmdir (name.left(strlen("/tmp/kmXXXXXX")).toLatin1()); 0089 } 0090 0091 const QString &cUnixSocket::getName () 0092 { 0093 return name; 0094 } 0095 0096 void cUnixSocket::readData (int) 0097 { 0098 if (!connected) 0099 { 0100 socklen_t sz = sizeof (sa); 0101 id2 = accept (id, (struct sockaddr *) &sa, &sz); 0102 if (id2 > -1) 0103 { 0104 connected = true; 0105 delete readnotifier; 0106 close (id); 0107 0108 fcntl (id2, O_NONBLOCK); 0109 0110 //then we create a pair of notifiers 0111 readnotifier = new QSocketNotifier (id2, QSocketNotifier::Read, this); 0112 writenotifier = new QSocketNotifier (id2, QSocketNotifier::Write, this); 0113 writenotifier->setEnabled (false); 0114 connect (readnotifier, SIGNAL (activated (int)), this, SLOT (readData (int))); 0115 connect (writenotifier, SIGNAL (activated (int)), this, SLOT (writeData (int))); 0116 } 0117 return; 0118 } 0119 0120 char buffer[201]; 0121 int n = read (id2, buffer, 200); 0122 buffer[n] = '\0'; 0123 if (n == -1) 0124 return; //bah 0125 if (n == 0) 0126 readnotifier->setEnabled (false); 0127 //hack: disable the notifier 0128 //(prevents problems on disconnect) 0129 for (int i = 0; i < n; i++) 0130 if (buffer[i] != '\n') 0131 readCache += QChar (buffer[i]); 0132 else 0133 { 0134 QString type = readCache.section (' ', 0, 0, QString::SectionSkipEmpty); 0135 QString data = readCache.section (' ', 1, -1, QString::SectionSkipEmpty); 0136 processRequest (type, data); 0137 readCache = QString::null; 0138 } 0139 } 0140 0141 void cUnixSocket::writeData (int) 0142 { 0143 int len = writeCache.length(); 0144 if (len == 0) 0145 return; //nothing to write 0146 int n = write (id2, writeCache.toLatin1(), len); 0147 //if n is -1, nothing was written and we'll send the data when the write 0148 //notifier ask us to do so (it may never happen, if the socket was closed 0149 //by the script, but that's not a problem) 0150 if (n > -1) 0151 //remove the part that was successfully sent 0152 writeCache.remove (0, n); 0153 0154 if (writeCache.isEmpty()) //nothing more to write 0155 writenotifier->setEnabled (false); 0156 } 0157 0158 void cUnixSocket::processRequest (const QString &type, const QString &data) 0159 { 0160 //scripts only exist in profile-based connections, so we can assume 0161 //that cConnPrefs object exists 0162 cRunningList *list = dynamic_cast<cRunningList *>(cActionManager::self()->object ("runninglist", sess)); 0163 0164 /* 0165 Request types that are currently supported: 0166 get - get a variable value 0167 set - set a variable value 0168 unset - unset a variable 0169 inc - increase a variable 0170 dec - decrease a variable 0171 request - request a resource 0172 provide - provide a resource 0173 lock - lock a variable 0174 unlock - remove a lock 0175 send - send a command to the MUD 0176 */ 0177 if (type == "get") 0178 { 0179 QString value = varlist->getValue (data); 0180 sendResult (value); 0181 } 0182 if (type == "set") 0183 { 0184 QString varname = data.section (' ', 0, 0, QString::SectionSkipEmpty); 0185 QString value = data.section (' ', 1, -1, QString::SectionSkipEmpty); 0186 if (list->canModify (script, varname)) 0187 { 0188 varlist->set (varname, value); 0189 sendResult ("OK"); 0190 } 0191 else 0192 sendResult ("FAIL"); 0193 } 0194 if (type == "unset") 0195 { 0196 if (list->canModify (script, data)) 0197 { 0198 varlist->unset (data); 0199 sendResult ("OK"); 0200 } 0201 else 0202 sendResult ("FAIL"); 0203 } 0204 if (type == "inc") 0205 { 0206 QString varname = data.section (' ', 0, 0, QString::SectionSkipEmpty); 0207 QString value = data.section (' ', 1, 1, QString::SectionSkipEmpty); 0208 bool ok; 0209 int num = value.toInt (&ok); 0210 if (!ok) //not a number 0211 { 0212 sendResult ("FAIL"); 0213 return; 0214 } 0215 if (num <= 0) //bad number 0216 { 0217 sendResult ("FAIL"); 0218 return; 0219 } 0220 0221 if (list->canModify (script, varname)) 0222 { 0223 varlist->inc (varname, num); 0224 sendResult ("OK"); 0225 } 0226 else 0227 sendResult ("FAIL"); 0228 } 0229 if (type == "dec") 0230 { 0231 QString varname = data.section (' ', 0, 0, QString::SectionSkipEmpty); 0232 QString value = data.section (' ', 1, 1, QString::SectionSkipEmpty); 0233 bool ok; 0234 int num = value.toInt (&ok); 0235 if (!ok) //not a number 0236 { 0237 sendResult ("FAIL"); 0238 return; 0239 } 0240 if (num <= 0) //bad number 0241 { 0242 sendResult ("FAIL"); 0243 return; 0244 } 0245 if (list->canModify (script, varname)) 0246 { 0247 varlist->dec (varname, num); 0248 sendResult ("OK"); 0249 } 0250 else 0251 sendResult ("FAIL"); 0252 } 0253 if (type == "request") 0254 { 0255 if (list->canModify (script, data)) 0256 { 0257 if (varlist->requestResource (data)) 0258 sendResult ("OK"); 0259 else 0260 sendResult ("FAIL"); 0261 } 0262 else 0263 sendResult ("FAIL"); 0264 } 0265 if (type == "provide") 0266 { 0267 if (list->canModify (script, data)) 0268 { 0269 varlist->provideResource (data); 0270 sendResult ("OK"); 0271 } 0272 else 0273 sendResult ("FAIL"); 0274 } 0275 if (type == "lock") 0276 { 0277 if (list->requestLock (script, data)) 0278 sendResult ("OK"); 0279 else 0280 sendResult ("FAIL"); 0281 } 0282 if (type == "unlock") 0283 { 0284 list->releaseLock (script, data); 0285 sendResult ("OK"); 0286 } 0287 if (type == "send") 0288 { 0289 cActionManager::self()->invokeEvent ("command", sess, data); 0290 0291 sendResult ("OK"); 0292 } 0293 } 0294 0295 void cUnixSocket::sendResult (const QString &result) 0296 { 0297 writenotifier->setEnabled (true); 0298 0299 writeCache = result + "\n"; 0300 writeData (id); 0301 } 0302 0303 #include "moc_cunixsocket.cpp"