func conntectionWriteAnswer( connection net.Conn, answerChannel *chan protocol.ServerCmd, thisConnectionInfo *connectionInfo, statistic *RlStatistic) { // async write to connection from answer channel active := true var answer *string // clientLabel := thisConnectionInfo.GetLabel() rllogger.Outputf(rllogger.LogDebug, " open writer to %s", clientLabel) for active { answer = nil serverCmd := <-*answerChannel if answerDataPtr, dumpErr := serverCmd.Dump(); dumpErr != nil { rllogger.Outputf( rllogger.LogError, "Dump answer error: %s from %s", dumpErr, clientLabel) answer = protocol.FastErrorAnswer(dumpErr, protocol.ErrCodeFormatProblem) } else { answer = answerDataPtr } active = thisConnectionInfo.IsActive() if active && answer != nil { writen, err := connection.Write([]byte(*answer)) if err != nil { active = false rllogger.Outputf( rllogger.LogError, "Can't send answer to %s error: %s", clientLabel, err) } else { // if this is last command after channel closing active = !serverCmd.IsEmpty() statistic.Append(StatOutcomeDataSize, writen) } } } rllogger.Outputf(rllogger.LogDebug, " closed writer to %s", clientLabel) }
func connectionHandler( server *RlServer, toCoreBuffer *chan protocol.CoreMsg, connection net.Conn, label string, dispatcher *AnswerDispatcher, stat *RlStatistic) { // server and service connections defer connection.Close() options := server.GetOption() connectionContext := helpers.ConnectionContext{} buffer := bufio.NewReader(connection) wait := true answerWriterActive := false var answer *string answerBuffer := make(chan protocol.ServerCmd, options.BufferSize) localConnectionInfo := newConnectionInfo(label) for wait { line, _, err := buffer.ReadLine() answer = nil if err != nil { if err == io.EOF { // client break connection localConnectionInfo.SetActive(false) if cid, exists := connectionContext.GetCid(); exists { dispatcher.RemoveChannel(cid, true) } } wait = false } else { stat.Append(StatIncomeDataSize, len(line)) cmd, err := protocol.NewClientCmd(&line) if err != nil { wait = false rllogger.Outputf( rllogger.LogWarn, "Incorrect command from %s error: %s", label, err) answer = protocol.FastErrorAnswer(err, protocol.ErrCodeFormatProblem) } else { if cmd.RequiredClose() { wait = false rllogger.Outputf(rllogger.LogInfo, "close command from %s", label) } else { // check auth if cmd.RequiredAuth() && !connectionContext.IsAuth() { answer = protocol.FastErrorAnswer( "Access denied!", protocol.ErrCodeAccessDenied) } else { // try get fast handler if exists, handler := cmd.GetFastHandler(); exists { if newAnswer, err := handler(cmd, &connectionContext, options); err != nil { rllogger.Outputf( rllogger.LogWarn, "Client: %s target: %d Handler error: %s", label, cmd.Target, err) answer = protocol.FastErrorAnswer(err, protocol.ErrCodeProtocolProblem) } else { if dataPtr, dumpErr := newAnswer.Dump(); dumpErr != nil { answer = protocol.FastErrorAnswer(err, protocol.ErrCodeImplementationProblem) } else { answer = dataPtr if exists, contextUpdater := newAnswer.GetContextUpdater(); exists { contextUpdater.Update(&connectionContext) rllogger.Outputf( rllogger.LogDebug, "-> %s context updated: %s", label, connectionContext) } } } } else { clientGroup := connectionContext.GetClientGroup() msg, convertError := protocol.NewCoreMsg(clientGroup, cmd) if convertError != nil { rllogger.Outputf( rllogger.LogWarn, "Msg create error: %s from %s", convertError, label) answer = protocol.FastErrorAnswer( convertError, protocol.ErrCodeProtocolProblem) } else { *toCoreBuffer <- *msg if !answerWriterActive { answerWriterActive = true // this channel to dispatcher dispatcher.AddChannel((*msg).Cid, &answerBuffer) // run async answer writer go conntectionWriteAnswer( connection, &answerBuffer, localConnectionInfo, stat) } } } } } } // write sync handler answer if answer != nil { writen, err := connection.Write([]byte(*answer)) if err != nil { rllogger.Outputf( rllogger.LogError, "Can't send answer to %s error: %s", label, err) } else { stat.Append(StatOutcomeDataSize, writen) } } } } //not need "close(answerBuffer)" dispatcher do it stat.Append(StatConnectionCount, -1) server.ChangeConnectionCount(-1) }