示例#1
0
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)
}
示例#2
0
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)
}