/[svn]/linuxsampler/trunk/src/network/lscpserver.cpp
ViewVC logotype

Diff of /linuxsampler/trunk/src/network/lscpserver.cpp

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

revision 2516 by schoenebeck, Thu Feb 6 21:11:23 2014 UTC revision 2534 by schoenebeck, Sun Mar 9 21:34:03 2014 UTC
# Line 47  Line 47 
47    
48  namespace LinuxSampler {  namespace LinuxSampler {
49    
50  String lscpParserProcessShellInteraction(String& line, yyparse_param_t* param);  String lscpParserProcessShellInteraction(String& line, yyparse_param_t* param, bool possibilities);
51    
52  /**  /**
53   * Returns a copy of the given string where all special characters are   * Returns a copy of the given string where all special characters are
# Line 716  extern yyparse_param_t* GetCurrentYaccSe Line 716  extern yyparse_param_t* GetCurrentYaccSe
716  }  }
717    
718  /**  /**
719     * Generate the relevant LSCP documentation reference section if necessary.
720     * The documentation section for the currently active command on the LSCP
721     * shell's command line will be encoded in a special format, specifically for
722     * the LSCP shell application.
723     *
724     * @param line - current LSCP command line
725     * @param param - reentrant Bison parser parameters
726     *
727     * @return encoded reference string or empty string if nothing shall be sent
728     *         to LSCP shell (client) at this point
729     */
730    String LSCPServer::generateLSCPDocReply(const String& line, yyparse_param_t* param) {
731        String result;
732        lscp_ref_entry_t* ref = lscp_reference_for_command(line.c_str());
733        // Pointer comparison works here, since the function above always
734        // returns the same constant pointer for the respective LSCP
735        // command ... Only send the LSCP reference section to the client if
736        // another LSCP reference section became relevant now:
737        if (ref != param->pLSCPDocRef) {
738            param->pLSCPDocRef = ref;
739            if (ref) { // send a new LSCP doc section to client ...
740                result += "SHD:" + ToString(LSCP_SHD_MATCH) + ":" + String(ref->name) + "\n";
741                result += String(ref->section) + "\n";
742                result += "."; // dot line marks the end of the text for client
743            } else { // inform client that no LSCP doc section matches right now ...
744                result = "SHD:" + ToString(LSCP_SHD_NO_MATCH);
745            }
746        }
747        dmsg(4,("LSCP doc reply -> '%s'\n", result.c_str()));
748        return result;
749    }
750    
751    /**
752   * Will be called to try to read the command from the socket   * Will be called to try to read the command from the socket
753   * If command is read, it will return true. Otherwise false is returned.   * If command is read, it will return true. Otherwise false is returned.
754   * In any case the received portion (complete or incomplete) is saved into bufferedCommand map.   * In any case the received portion (complete or incomplete) is saved into bufferedCommand map.
755   */   */
756  bool LSCPServer::GetLSCPCommand( std::vector<yyparse_param_t>::iterator iter ) {  bool LSCPServer::GetLSCPCommand( std::vector<yyparse_param_t>::iterator iter ) {
757          int socket = (*iter).hSession;          int socket = (*iter).hSession;
758            int result;
759          char c;          char c;
760          int i = 0;          std::vector<char> input;
761    
762            // first get as many character as possible and add it to the 'input' buffer
763          while (true) {          while (true) {
764                  #if defined(WIN32)                  #if defined(WIN32)
765                  int result = recv(socket, (char *)&c, 1, 0); //Read one character at a time for now                  result = recv(socket, (char *)&c, 1, 0); //Read one character at a time for now
766                  #else                  #else
767                  int result = recv(socket, (void *)&c, 1, 0); //Read one character at a time for now                  result = recv(socket, (void *)&c, 1, 0); //Read one character at a time for now
768                  #endif                  #endif
769                  if (result == 0) { //socket was selected, so 0 here means client has closed the connection                  if (result == 1) input.push_back(c);
770                          CloseConnection(iter);                  else break; // end of input or some error
771                          break;                  if (c == '\n') break; // process line by line
772                  }          }
773                  if (result == 1) {  
774                          if (c == '\r')          // process input buffer
775                                  continue; //Ignore CR          for (int i = 0; i < input.size(); ++i) {
776                          if (c == '\n') {                  c = input[i];
777                                  LSCPServer::SendLSCPNotify(LSCPEvent(LSCPEvent::event_misc, "Received \'" + bufferedCommands[socket] + "\' on socket", socket));                  if (c == '\r') continue; //Ignore CR
778                                  bufferedCommands[socket] += "\r\n";                  if (c == '\n') {
                                 return true; //Complete command was read  
                         }  
                         // backspace character - should only happen with shell  
                         if (c == '\b') {  
                                 if (!bufferedCommands[socket].empty()) {  
                                         bufferedCommands[socket] = bufferedCommands[socket].substr(  
                                                 0, bufferedCommands[socket].length() - 1  
                                         );  
                                 }  
                         } else bufferedCommands[socket] += c;  
779                          // only if the other side is the LSCP shell application:                          // only if the other side is the LSCP shell application:
780                          // check the current (incomplete) command line for syntax errors,                          // check the current (incomplete) command line for syntax errors,
781                          // possible completions and report everything back to the shell                          // possible completions and report everything back to the shell
782                          if ((*iter).bShellInteract || (*iter).bShellAutoCorrect) {                          if ((*iter).bShellInteract || (*iter).bShellAutoCorrect) {
783                                  String s = lscpParserProcessShellInteraction(bufferedCommands[socket], &(*iter));                                  String s = lscpParserProcessShellInteraction(bufferedCommands[socket], &(*iter), false);
784                                  if (!s.empty() && (*iter).bShellInteract) AnswerClient(s + "\n");                                  if (!s.empty() && (*iter).bShellInteract) AnswerClient(s + "\n");
785                          }                          }
786                            // if other side is LSCP shell application, send the relevant LSCP
787                            // documentation section of the current command line (if necessary)
788                            if ((*iter).bShellSendLSCPDoc && (*iter).bShellInteract) {
789                                    String s = generateLSCPDocReply(bufferedCommands[socket], &(*iter));
790                                    if (!s.empty()) AnswerClient(s + "\n");
791                            }
792                            LSCPServer::SendLSCPNotify(LSCPEvent(LSCPEvent::event_misc, "Received \'" + bufferedCommands[socket] + "\' on socket", socket));
793                            bufferedCommands[socket] += "\r\n";
794                            return true; //Complete command was read
795                    } else if (c == 2) { // custom ASCII code usage for moving cursor left (LSCP shell)
796                            if (iter->iCursorOffset + bufferedCommands[socket].size() > 0)
797                                    iter->iCursorOffset--;
798                    } else if (c == 3) { // custom ASCII code usage for moving cursor right (LSCP shell)
799                            if (iter->iCursorOffset < 0) iter->iCursorOffset++;
800                    } else {
801                            size_t cursorPos = bufferedCommands[socket].size() + iter->iCursorOffset;
802                            // backspace character - should only happen with shell
803                            if (c == '\b') {
804                                    if (!bufferedCommands[socket].empty() && cursorPos > 0)
805                                            bufferedCommands[socket].erase(cursorPos - 1, 1);
806                            } else { // append (or insert) new character (at current cursor position) ...
807                                    if (cursorPos >= 0)
808                                            bufferedCommands[socket].insert(cursorPos, String(1,c)); // insert
809                                    else
810                                            bufferedCommands[socket] += c; // append
811                            }
812                  }                  }
813                  #if defined(WIN32)                  // only if the other side is the LSCP shell application:
814                  if (result == SOCKET_ERROR) {                  // check the current (incomplete) command line for syntax errors,
815                      int wsa_lasterror = WSAGetLastError();                  // possible completions and report everything back to the shell
816                          if (wsa_lasterror == WSAEWOULDBLOCK) //Would block, try again later.                  if ((*iter).bShellInteract || (*iter).bShellAutoCorrect) {
817                                  return false;                          String s = lscpParserProcessShellInteraction(bufferedCommands[socket], &(*iter), true);
818                          dmsg(2,("LSCPScanner: Socket error after recv() Error %d.\n", wsa_lasterror));                          if (!s.empty() && (*iter).bShellInteract && i == input.size() - 1)
819                          CloseConnection(iter);                                  AnswerClient(s + "\n");
                         break;  
820                  }                  }
821                  #else                  // if other side is LSCP shell application, send the relevant LSCP
822                  if (result == -1) {                  // documentation section of the current command line (if necessary)
823                          if (errno == EAGAIN) //Would block, try again later.                  if ((*iter).bShellSendLSCPDoc && (*iter).bShellInteract) {
824                            String s = generateLSCPDocReply(bufferedCommands[socket], &(*iter));
825                            if (!s.empty()) AnswerClient(s + "\n");
826                    }
827            }
828    
829            // handle network errors ...
830            if (result == 0) { //socket was selected, so 0 here means client has closed the connection
831                    CloseConnection(iter);
832                    return false;
833            }
834            #if defined(WIN32)
835            if (result == SOCKET_ERROR) {
836                    int wsa_lasterror = WSAGetLastError();
837                    if (wsa_lasterror == WSAEWOULDBLOCK) //Would block, try again later.
838                            return false;
839                    dmsg(2,("LSCPScanner: Socket error after recv() Error %d.\n", wsa_lasterror));
840                    CloseConnection(iter);
841                    return false;
842            }
843            #else
844            if (result == -1) {
845                    if (errno == EAGAIN) //Would block, try again later.
846                            return false;
847                    switch(errno) {
848                            case EBADF:
849                                    dmsg(2,("LSCPScanner: The argument s is an invalid descriptor.\n"));
850                                    return false;
851                            case ECONNREFUSED:
852                                    dmsg(2,("LSCPScanner: A remote host refused to allow the network connection (typically because it is not running the requested service).\n"));
853                                    return false;
854                            case ENOTCONN:
855                                    dmsg(2,("LSCPScanner: The socket is associated with a connection-oriented protocol and has not been connected (see connect(2) and accept(2)).\n"));
856                                    return false;
857                            case ENOTSOCK:
858                                    dmsg(2,("LSCPScanner: The argument s does not refer to a socket.\n"));
859                                    return false;
860                            case EAGAIN:
861                                    dmsg(2,("LSCPScanner: The socket is marked non-blocking and the receive operation would block, or a receive timeout had been set and the timeout expired before data was received.\n"));
862                                    return false;
863                            case EINTR:
864                                    dmsg(2,("LSCPScanner: The receive was interrupted by delivery of a signal before any data were available.\n"));
865                                    return false;
866                            case EFAULT:
867                                    dmsg(2,("LSCPScanner: The receive buffer pointer(s) point outside the process's address space.\n"));
868                                    return false;
869                            case EINVAL:
870                                    dmsg(2,("LSCPScanner: Invalid argument passed.\n"));
871                                    return false;
872                            case ENOMEM:
873                                    dmsg(2,("LSCPScanner: Could not allocate memory for recvmsg.\n"));
874                                    return false;
875                            default:
876                                    dmsg(2,("LSCPScanner: Unknown recv() error.\n"));
877                                  return false;                                  return false;
                         switch(errno) {  
                                 case EBADF:  
                                         dmsg(2,("LSCPScanner: The argument s is an invalid descriptor.\n"));  
                                         break;  
                                 case ECONNREFUSED:  
                                         dmsg(2,("LSCPScanner: A remote host refused to allow the network connection (typically because it is not running the requested service).\n"));  
                                         break;  
                                 case ENOTCONN:  
                                         dmsg(2,("LSCPScanner: The socket is associated with a connection-oriented protocol and has not been connected (see connect(2) and accept(2)).\n"));  
                                         break;  
                                 case ENOTSOCK:  
                                         dmsg(2,("LSCPScanner: The argument s does not refer to a socket.\n"));  
                                         break;  
                                 case EAGAIN:  
                                         dmsg(2,("LSCPScanner: The socket is marked non-blocking and the receive operation would block, or a receive timeout had been set and the timeout expired before data was received.\n"));  
                                         break;  
                                 case EINTR:  
                                         dmsg(2,("LSCPScanner: The receive was interrupted by delivery of a signal before any data were available.\n"));  
                                         break;  
                                 case EFAULT:  
                                         dmsg(2,("LSCPScanner: The receive buffer pointer(s) point outside the process's address space.\n"));  
                                         break;  
                                 case EINVAL:  
                                         dmsg(2,("LSCPScanner: Invalid argument passed.\n"));  
                                         break;  
                                 case ENOMEM:  
                                         dmsg(2,("LSCPScanner: Could not allocate memory for recvmsg.\n"));  
                                         break;  
                                 default:  
                                         dmsg(2,("LSCPScanner: Unknown recv() error.\n"));  
                                         break;  
                         }  
                         CloseConnection(iter);  
                         break;  
878                  }                  }
879                  #endif                  CloseConnection(iter);
880                    return false;
881          }          }
882            #endif
883    
884          return false;          return false;
885  }  }
886    
# Line 4019  String LSCPServer::SetShellAutoCorrect(y Line 4092  String LSCPServer::SetShellAutoCorrect(y
4092          else throw Exception("Not a boolean value, must either be 0 or 1");          else throw Exception("Not a boolean value, must either be 0 or 1");
4093      } catch (Exception e) {      } catch (Exception e) {
4094          result.Error(e);          result.Error(e);
4095        }
4096        return result.Produce();
4097    }
4098    
4099    String LSCPServer::SetShellDoc(yyparse_param_t* pSession, double boolean_value) {
4100        dmsg(2,("LSCPServer: SetShellDoc(val=%f)\n", boolean_value));
4101        LSCPResultSet result;
4102        try {
4103            if      (boolean_value == 0) pSession->bShellSendLSCPDoc = false;
4104            else if (boolean_value == 1) pSession->bShellSendLSCPDoc = true;
4105            else throw Exception("Not a boolean value, must either be 0 or 1");
4106        } catch (Exception e) {
4107            result.Error(e);
4108      }      }
4109      return result.Produce();      return result.Produce();
4110  }  }

Legend:
Removed from v.2516  
changed lines
  Added in v.2534

  ViewVC Help
Powered by ViewVC