#include #include #include #include #include #include #ifdef WIN32 #include #include /* http://predef.sourceforge.net/precomp.html */ #if (!((defined(_MSC_VER)) && (_MSC_VER < 1300))) #include #endif #include #else #include #include #endif #include "version.h" #include "ClientServerMapper.h" /* Macro for debug printouts */ #ifdef DEBUG #define D(x) x #else #define D(x) #endif const char* ClientStateAndData::identifier = "eitcp"; // This class takes care of one client. ClientStateAndData::ClientStateAndData(Hcb *hca, int perm): state(ID_STATE), hcaBuffer(hca), hcaBuffer2(NULL), permanent(perm) { sendStr("www.eit.se/hcpips\r\n"); }; ClientStateAndData::~ClientStateAndData() { if (hcaBuffer) { delete hcaBuffer; } if (hcaBuffer2) { delete hcaBuffer2; } } void ClientStateAndData::sendInt(int i) { char str[40]; //itoa(i, str, 10); sprintf(str,"%d",i); sendStr(str); } void ClientStateAndData::sendBuffer(const char* bufPtr, const int bufLen) { char *ptr=hcaBuffer->getWritePtr(bufLen); memcpy(ptr, bufPtr, bufLen); hcaBuffer->writeDone(ptr, bufLen); } void ClientStateAndData::processInOut() { if (hcaBuffer) { if (hcaBuffer->process()<0) { delete hcaBuffer; hcaBuffer=NULL; delete hcaBuffer2; hcaBuffer2=NULL; } } if (hcaBuffer2) { if (hcaBuffer2->process()<0) { delete hcaBuffer2; hcaBuffer2=NULL; } } } // called when there is data to read for the client // returns <0 if it is done. int ClientStateAndData::process() { processInOut(); switch(state) { case ID_STATE: { if (hcaBuffer==NULL) { state=DISCONNECTED_STATE; } else if (hcaBuffer->isReadyForRead()) { int r=0; const char *str=hcaBuffer->getReadPtr(); if (strcmp(str, identifier)==0) { D(fprintf(stderr,"client identification accepted\n")); sendStr(CMD_OK END_LINE); state=COMMAND_STATE; } else { fprintf(stderr, "failed, wrong identifier\n"); sendStr(CMD_FAIL " wrong identifier\r\n"); r=0; } hcaBuffer->readDone(str); if (r<0) { return r; } } break; } case COMMAND_STATE: { if (hcaBuffer==NULL) { state=DISCONNECTED_STATE; } else if (hcaBuffer->isReadyForRead()) { const char *str=hcaBuffer->getReadPtr(); const int r=parseCmd(str); hcaBuffer->readDone(str); if (r<0) { return r; } } break; } case CONNECTED_STATE: { if (hcaBuffer==NULL) { state=DISCONNECTED_STATE; } else if (hcaBuffer2==NULL) { if (permanent) { hcaBuffer->setCononicalMode(); sendStr(CMD_FAIL "disconnected" END_LINE); state=ID_STATE; } else { state=DISCONNECTED_STATE; } } else { if (hcaBuffer->isReadyForRead()) { const char *str=hcaBuffer->getReadPtr(); const int len=hcaBuffer->getReadLen(); char *str2=hcaBuffer2->getWritePtr(len); memcpy(str2, str, len); hcaBuffer2->writeDone(str2, len); hcaBuffer->readDone(str); } if (hcaBuffer2->isReadyForRead()) { const char *str=hcaBuffer2->getReadPtr(); const int len=hcaBuffer2->getReadLen(); char *str2=hcaBuffer->getWritePtr(len); memcpy(str2, str, len); hcaBuffer->writeDone(str2, len); hcaBuffer2->readDone(str); } } break; } case DISCONNECTED_STATE: { printf("disconnected\n"); return -1; } default: { printf("unknown state %d\n", state); return -1; } } // switch processInOut(); return 0; } /* void ClientStateAndData::close() { hcaBuffer->close(); }; */ void ClientStateAndData::help() { sendStr(PREFIX "commands:\r\n"); sendStr(PREFIX "? : help\r\n"); sendStr(PREFIX "c : connect to tcp/ip port:\r\n"); sendStr(PREFIX "p : connect to serial port\r\n"); sendStr(PREFIX "d : disconnect\r\n"); sendStr(PREFIX "e : echo on\r\n"); sendStr(PREFIX "s : echo off\r\n"); sendStr(PREFIX "k : kill server\r\n"); sendStr(PREFIX "v : give server version\r\n"); #ifdef WIN32 sendStr(PREFIX "l [class]: list all class device names, class can be \"Ports\"\r\n"); sendStr(PREFIX "r : list available serial comm ports\r\n"); #endif sendStr(PREFIX "n : list available serial comm ports (only name)\r\n"); sendStr(PREFIX "i : show server os\r\n"); sendStr(CMD_OK END_LINE); } // returns -1 if exit disconnected int ClientStateAndData::parseCmd(const char *cmdLine) { D(fprintf(stderr,"parse cmdLine %.256s\r\n", cmdLine)); int argc; char buffer[2000]; char *argv_p[64]={NULL}; argc=parseArgsInCommandLine(cmdLine, buffer, sizeof(buffer), argv_p, SIZE_OF_ARRAY(argv_p)); if (argc>0) { switch (*argv_p[0]) { case '?': help();break; case 'v': sendStr(PREFIX VERSION END_LINE CMD_OK END_LINE);break; //case 'o': sendStr("ogm:\r\n");sendBuffer(ogm, ogm_len);break; case 'c': { if (argc<3) { sendStr(CMD_FAIL " to few arguments\r\n"); } else { unsigned short port=atoi(argv_p[2]); Hcb *hca=Hcb::client(argv_p[1], port); if (hca!=NULL) { sendStr(CMD_OK END_LINE); hcaBuffer2=hca; hcaBuffer->setTransparentMode(); hcaBuffer2->setTransparentMode(); state=CONNECTED_STATE; } else { sendStr(CMD_FAIL " could not connect\r\n"); } } break; } case 'p': { if (argc<3) { sendStr(CMD_FAIL " to few arguments\r\n"); } else { int baudrate=atoi(argv_p[2]); Hcb *hca=Hcb::open_serial_port(argv_p[1], baudrate); if (hca!=NULL) { sendStr(CMD_OK END_LINE); hcaBuffer2=hca; hcaBuffer->setTransparentMode(); hcaBuffer2->setTransparentMode(); state=CONNECTED_STATE; } else { sendStr(CMD_FAIL " could not open port\r\n"); } } break; } case 'e': { hcaBuffer->activateEcho(); sendStr(PREFIX "echo on" END_LINE CMD_OK END_LINE); break; } case 's': { hcaBuffer->deactivateEcho(); sendStr(PREFIX "echo off" END_LINE CMD_OK END_LINE); break; } case 'd': { D(fprintf(stderr,"disconnect\r\n")); sendStr(PREFIX "disconnect" END_LINE CMD_OK END_LINE); return -1; } case 'k': { D(fprintf(stderr,"kill\r\n")); sendStr(PREFIX "kill" END_LINE CMD_OK END_LINE); return -2;; break; } case 'l': { dev_list(argv_p[1]); break; } case 'r': { reg_list(); break; } case 'n': { reg_list_name(); break; } case 'i': { serverInfo(); break; } case 't': { if (argc<2) { sendStr(CMD_FAIL " to few arguments\r\n"); } else { int n=atoi(argv_p[1]); while (n>0) { sendStr(PREFIX " testing sending many lines "); sendInt(n); sendStr(END_LINE); n--; } sendStr(CMD_OK END_LINE); } break; } default: { char str[80]; sprintf(str, CMD_FAIL " unknown command '%.256s'\r\n", argv_p[0]); sendStr(str);break; } }; } return 0; }; void ClientStateAndData::dev_list(const char *filter) { #if ((defined(WIN32)) && !((defined(_MSC_VER)) && (_MSC_VER < 1300))) // http://www.codeproject.com/KB/system/SimpleSetup.aspx HWND _hDlg = 0; HDEVINFO hDevInfo = SetupDiGetClassDevs(0L, //Retrieve all classes 0L, // no enumerator _hDlg, // Parent Windows, usually set to “0” //control options used in building the device information set DIGCF_PRESENT | DIGCF_ALLCLASSES | DIGCF_PROFILE); if(hDevInfo == INVALID_HANDLE_VALUE) { DWORD Err = GetLastError(); fprintf(stderr, "SetupDiGetClassDevs failed: %lx.\n", Err ); sendStr(CMD_FAIL " SetupDiGetClassDevs" END_LINE); return; } //sendStr(PREFIX "Device names:\r\n"); DWORD wIndex = 0; _SP_DEVINFO_DATA spDevInfoData; spDevInfoData.cbSize = sizeof(SP_DEVINFO_DATA); while (1) { if (SetupDiEnumDeviceInfo(hDevInfo, wIndex, &spDevInfoData)) { //if (spDevInfoData.ClassGuid.Data1==0x4d36e978) bool print=false; if ((filter) && (*filter)) { byte szBuf[2048]; if (SetupDiGetDeviceRegistryProperty(hDevInfo, &spDevInfoData, SPDRP_CLASS, //Retrieve property type, 0L, szBuf, sizeof(szBuf), 0)) { if (strcmp(filter, (char*)szBuf)==0) { print=true; } } } else { print=true; } if (print) { byte szBuf[2048]; if (SetupDiGetDeviceRegistryProperty(hDevInfo, &spDevInfoData, SPDRP_FRIENDLYNAME, //Retrieve property type, 0L, szBuf, sizeof(szBuf), 0)) { #if 1 sendStr(PREFIX); sendStr((char*)szBuf); sendStr(END_LINE); #else sendStr(END_LINE); for(int i=0; i<25;i++) { if (SetupDiGetDeviceRegistryProperty(hDevInfo, &spDevInfoData, i, //Retrieve property type, 0L, szBuf, sizeof(szBuf), 0)) { if (isprint(*szBuf)) { sendInt(i); sendStr(PREFIX); sendStr((char*)szBuf); sendStr(END_LINE); } } } sendStr(END_LINE); #endif }; } } else { sendStr(CMD_OK END_LINE); break; } wIndex++; }; #else sendStr(CMD_FAIL " not supported in this version" END_LINE); #endif } void ClientStateAndData::reg_list() { #ifdef WIN32 //sendStr("Available serial comm ports:\r\n"); LPCTSTR lpSubKey = "HARDWARE\\DEVICEMAP\\SERIALCOMM"; REGSAM samDesired = KEY_QUERY_VALUE; HKEY hKey = 0; if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, lpSubKey, 0, samDesired, &hKey)!=ERROR_SUCCESS) { sendStr(CMD_FAIL " RegOpenKeyEx" END_LINE); } else { DWORD dwIndex=0; for(;;) { char name[2048]; DWORD nameLen=sizeof(name); char buf[2048]; DWORD bufLen=sizeof(buf); const LONG r = RegEnumValue(hKey , dwIndex, (LPTSTR)name, &nameLen, NULL, NULL, (LPBYTE)buf, &bufLen); if (r!=ERROR_SUCCESS) { break; } else { sendStr(PREFIX); sendBuffer(name, nameLen); sendStr(" "); sendBuffer(buf, bufLen); sendStr(END_LINE); } dwIndex++; } RegCloseKey(hKey); } sendStr(CMD_OK END_LINE); #else sendStr(CMD_FAIL " not supported on this os\r\n"); #endif } void ClientStateAndData::reg_list_name() { #ifdef WIN32 //sendStr("Available serial comm ports:\r\n"); LPCTSTR lpSubKey = "HARDWARE\\DEVICEMAP\\SERIALCOMM"; REGSAM samDesired = KEY_QUERY_VALUE; HKEY hKey = 0; if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, lpSubKey, 0, samDesired, &hKey)!=ERROR_SUCCESS) { sendStr(CMD_FAIL " RegOpenKeyEx" END_LINE); } else { DWORD dwIndex=0; for(;;) { char name[2048]; DWORD nameLen=sizeof(name); char buf[2048]; DWORD bufLen=sizeof(buf); const LONG r = RegEnumValue(hKey , dwIndex, (LPTSTR)name, &nameLen, NULL, NULL, (LPBYTE)buf, &bufLen); if (r!=ERROR_SUCCESS) { break; } else { sendStr(PREFIX); /*sendBuffer(name, nameLen); sendStr(" ");*/ sendBuffer(buf, bufLen); sendStr(END_LINE); } dwIndex++; } RegCloseKey(hKey); } sendStr(CMD_OK END_LINE); #else /* Serial Port Files From: http://www.easysw.com/~mike/serial/serial.html#advanced System Port 1 Port 2 IRIX® /dev/ttyf1 /dev/ttyf2 HP-UX /dev/tty1p0 /dev/tty2p0 Solaris®/SunOS® /dev/ttya /dev/ttyb Linux® /dev/ttyS0 /dev/ttyS1 Digital UNIX® /dev/tty01 /dev/tty02 */ const char* d = "/dev"; const char* filter = "ttyS"; // If using another host than linux kernel this may need to be changed. DIR *dp = opendir(d); struct dirent64 *dirp; if (dp == NULL) { fprintf(stderr, "Error %d %s", errno, d); sendStr(CMD_FAIL " did not find /dev" END_LINE); } else { while ((dirp = readdir64(dp)) != NULL) { const char *n = dirp->d_name; if (memcmp(filter, n, strlen(filter))==0) { sendStr(PREFIX "/dev/"); sendStr(n); sendStr(END_LINE); } } closedir(dp); sendStr(CMD_OK END_LINE); } #endif } void ClientStateAndData::serverInfo() { #ifdef WIN32 LPCTSTR lpSubKey = "SYSTEM\\CurrentControlSet\\Control\\ProductOptions"; REGSAM samDesired = KEY_QUERY_VALUE/*KEY_READ*/; HKEY hKey = 0; if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, lpSubKey, 0, samDesired, &hKey)!=ERROR_SUCCESS) { sendStr(CMD_FAIL " RegOpenKeyEx" END_LINE); } else { char buf[1024]; DWORD bufLen=sizeof(buf); LONG r = RegQueryValueEx(hKey, "ProductType", NULL, NULL, (LPBYTE)buf, &bufLen); if (r!=ERROR_SUCCESS) { sendStr(CMD_FAIL " RegQueryValueEx" END_LINE); } else { sendStr(PREFIX "WIN32 "); sendBuffer(buf, bufLen); sendStr(END_LINE CMD_OK END_LINE); } RegCloseKey(hKey); } #else sendStr(PREFIX "not WIN32" END_LINE); sendStr(CMD_OK END_LINE); #endif } void ClientStateAndData::sendStr(const char *str) { const int len=strlen(str); D(fprintf(stderr,"sendStr %.256s" END_LINE, str)); sendBuffer(str, len); }