func isClientConfigRequest(requestName string) bool {
	if requestName == string(client_message.CLIENTCONFIGURATION) {
		return true
	}
	return false
}
Check if request name is client config request
package main
import (
	"github.com/shopspring/decimal"
	"bytes"
	"errors"
	"flag"
	"fmt"
	"net"
	"net/http"
	"os"
	"os/signal"
	"path/filepath"
	"strings"
	"sync"
	"syscall"
	"time"
	"encoding/json"
	"encoding/hex"
	"github.com/nttdots/go-dots/dots_common/messages"
	"github.com/nttdots/go-dots/dots_client/task"
	"github.com/nttdots/go-dots/libcoap"
	log "github.com/sirupsen/logrus"
	common "github.com/nttdots/go-dots/dots_common"
	dots_config "github.com/nttdots/go-dots/dots_client/config"
	client_message "github.com/nttdots/go-dots/dots_client/messages"
	restful_router "github.com/nttdots/go-dots/dots_client/router"
)
const (
	DEFAULT_DOTS_SERVER_ADDRESS = "127.0.0.1"
)
var (
	server            string
	serverIP          net.IP
	signalChannelPort int
	dataChannelPort   int
	socket            string
	certFile          string
	clientCertFile    string
	clientKeyFile     string
	identity          string
	psk               string
	configFile        string
	defaultConfigFile = "dots_client.yaml"
)
func init() {
	abs, _ := filepath.Abs(os.Args[0])
	execDir := filepath.Dir(abs)
	certPath := getDefaultCertPath(execDir)
	defaultCertFile := filepath.Join(certPath, "ca-cert.pem")
	defaultClientCertFile := filepath.Join(certPath, "client-cert.pem")
	defaultClientKeyFile := filepath.Join(certPath, "client-key.pem")
	flag.StringVar(&server, "server", DEFAULT_DOTS_SERVER_ADDRESS, "dots Server address")
	flag.IntVar(&signalChannelPort, "signalChannelPort", common.DEFAULT_SIGNAL_CHANNEL_PORT, "dots signal channel Server port")
	flag.IntVar(&dataChannelPort, "dataChannelPort", common.DEFAULT_DATA_CHANNEL_PORT, "dots data channel Server port")
	flag.StringVar(&socket, "socket", common.DEFAULT_CLIENT_SOCKET_FILE, "dots client socket")
	flag.StringVar(&certFile, "certFile", defaultCertFile, "cert file path")
	flag.StringVar(&clientCertFile, "clientCertFile", defaultClientCertFile, "client cert file path")
	flag.StringVar(&clientKeyFile, "clientKeyFile", defaultClientKeyFile, "client key file path")
	flag.StringVar(&identity, "identity", "", "identity for DTLS PSK")
	flag.StringVar(&psk, "psk", "", "DTLS PSK")
	flag.StringVar(&configFile, "config", defaultConfigFile, "config yaml file")
}
var signalChannelAddress string
var dataChannelAddress string
func connectSignalChannel(orgEnv *task.Env) (env *task.Env, err error) {
	var ctx *libcoap.Context
	var sess *libcoap.Session
	var oSess *libcoap.Session
	var addr libcoap.Address
	libcoap.Startup()
	addr, err = libcoap.AddressOf(serverIP, uint16(signalChannelPort))
	if err != nil {
		log.WithError(err).Error("AddressOf() failed")
		goto error
	}
	if 0 < len(psk) {
		log.WithField("identity", identity).WithField("psk", psk).Info("Using PSK")
		ctx = libcoap.NewContext(nil)
		if ctx == nil {
			log.Error("NewContext() -> nil")
			err = errors.New("NewContext() -> nil")
			goto error
		}
		sess = ctx.NewClientSessionPSK(addr, libcoap.ProtoDtls, identity, []byte(psk))
		if sess == nil {
			log.Error("NewClientSessionPSK() -> nil")
			err = errors.New("NewClientSessionPSK() -> nil")
			goto error
		}
	} else {
		dtlsParam := libcoap.DtlsParam { &certFile, nil, &clientCertFile, &clientKeyFile, config.PinnedCertificate }
		if orgEnv == nil {
			ctx = libcoap.NewContextDtls(nil, &dtlsParam, int(libcoap.CLIENT_PEER))
			if ctx == nil {
				log.Error("NewContextDtls() -> nil")
				err = errors.New("NewContextDtls() -> nil")
				goto error
			}
		} else {
			ctx = orgEnv.CoapContext()
		}
		sess = ctx.NewClientSessionDTLS(addr, libcoap.ProtoDtls)
		if sess == nil {
			if orgEnv == nil {
				log.Error("NewClientSessionDTLS() -> nil")
				err = errors.New("NewClientSessionDTLS() -> nil")
				goto error
			} else {
				log.Debug("NewClientSessionDTLS() -> nil. Retry re-create new DTLS session")
				connectSignalChannel(orgEnv)
			}
		}
	}
	if ctx != nil {
		resource := libcoap.ResourceUnknownInit()
		ctx.AddResource(resource)
		resource.RegisterServerHandler(libcoap.RequestPut, heartbeatHandler())
	}
	if (orgEnv == nil){
		env = task.NewEnv(ctx, sess)
	} else {
		oSess = orgEnv.CoapSession()
		env = orgEnv
	}
	ctx.RegisterEventHandler(func(_ *libcoap.Context, event libcoap.Event, session *libcoap.Session){
		if event == libcoap.EventSessionConnected {
			if orgEnv != nil {
				orgEnv.SetReplacingSession(session)
				env.SetIsServerStopped(false)
			}
		} else if event == libcoap.EventSessionDisconnected {
			if orgEnv == nil {
				log.Warn("Server is stopped. DOTS client can't connect to server")
				env.SetIsServerStopped(true)
				return
			}
			session.SessionRelease()
			restartConnection(env)
		}
	})
	ctx.RegisterResponseHandler(func(_ *libcoap.Context, _ *libcoap.Session, _ *libcoap.Pdu, received *libcoap.Pdu) {
		handleResponse(env, received)
		if received != nil && oSess != nil && oSess == env.CoapSession(){
			sess.SessionRelease()
			log.Debugf("Restarted connection successfully with current session: %+v.", oSess.String())
			env.Run(task.NewHeartBeatTask(
					time.Duration(config.DefaultSessionConfiguration.HeartbeatInterval) * time.Second,
					config.DefaultSessionConfiguration.MissingHbAllowed,
					time.Duration(config.DefaultSessionConfiguration.AckTimeout)* time.Second,
					heartbeatResponseHandler,
					heartbeatTimeoutHandler))
		}
	})
	ctx.RegisterNackHandler(func(_ *libcoap.Context, _ *libcoap.Session, sent *libcoap.Pdu, reason libcoap.NackReason) {
		if (reason == libcoap.NackRst){
			handleResponse(env, sent)
		} else if (reason == libcoap.NackTooManyRetries){
			handleRequestTimeout(env, sent)
		} else {
			log.Infof("nack_handler gets fired with unsupported reason type : %+v.", reason)
		}
	})
	return
error:
	cleanupSignalChannel(ctx, sess)
	return
}
func heartbeatHandler() libcoap.MethodHandler {
	return func(ctx *libcoap.Context, rsrc *libcoap.Resource, sess *libcoap.Session, request *libcoap.Pdu, token *[]byte, query *string, response *libcoap.Pdu) {
		log.Info("Handle receive heartbeat from server")
		log.Debugf("request.Data=\n%s", hex.Dump(request.Data))
		body, errMsg := messages.ValidateHeartBeatMechanism(request)
		response.MessageID = request.MessageID
        response.Token     = request.Token
		if body == nil && errMsg != "" {
			log.Error(errMsg)
			response.Code = libcoap.ResponseInternalServerError
			response.Type = libcoap.TypeNon
			response.Data = []byte(errMsg)
		} else if body != nil && errMsg != "" {
			log.Error(errMsg)
			response.Code = libcoap.ResponseBadRequest
			response.Type = libcoap.TypeNon
			response.Data = []byte(errMsg)
		} else {
			response.Code = libcoap.ResponseChanged
			response.Type = libcoap.TypeNon
		}
		log.Debugf("response=%+v", response)
		task.SetIsReceiveHeartBeat(true)
		return
	}
}
func cleanupSignalChannel(ctx *libcoap.Context, sess *libcoap.Session) {
	if ctx != nil {
		ctx.FreeContext()
	}
	libcoap.Cleanup()
}
func makeServerHandler(env *task.Env) http.HandlerFunc {
	return func (w http.ResponseWriter, r *http.Request) {
		var tmpPaths []string
		paths := strings.Split(r.URL.Path, "?")
		if len(paths) > 1 {
			tmpPaths = strings.Split(paths[0], "/")
			queryPaths := strings.Split(paths[1],"&")
			if len(queryPaths) > 1 {
				tmpPaths = append(tmpPaths, queryPaths...)
			} else {
				tmpPaths = append(tmpPaths, paths[1])
			}
		} else {
			tmpPaths = strings.Split(r.URL.Path, "/")
		}
		var requestName = ""
		var tmpPath string
		var requestQuerys []string
		for i := len(tmpPaths) - 1; i >=0; i-- {
			tmpPath = tmpPaths[i]
			if strings.Contains(tmpPath, "=") {
				continue
			}
			requestName = tmpPath
			requestQuerys = tmpPaths[i+1:]
			break
		}
		for _,query := range requestQuerys {
			querySplit := strings.Split(query, "cuid=")
			if len(querySplit) > 1 && len(querySplit[1]) > int(messages.CUID_LEN) {
				log.Warnf("The 'cuid' (%+v) should not be greater than 22 characters", len(querySplit[1]))
				return
			}
		}
		options := make(map[messages.Option]string)
		observeStr := r.Header.Get(string(messages.OBSERVE))
		if observeStr != "" {
			options[messages.OBSERVE] = observeStr
		}
		if val, ok := r.Header[string(messages.IFMATCH)]; ok {
			options[messages.IFMATCH] = val[0]
		}
		log.Debugf("Parsed URI, requestName=%+v, requestQuerys=%+v, options=%+v", requestName, requestQuerys, options)
		if requestName == "" || (!isClientConfigRequest(requestName) && !messages.IsRequest(requestName)) {
			fmt.Printf("dots_client.serverHandler -- %s is invalid request name \n", requestName)
			fmt.Printf("support messages: %s \n", messages.SupportRequest())
			errMessage := fmt.Sprintf("%s is invalid request name \n", requestName)
			w.WriteHeader(http.StatusBadRequest)
			w.Write([]byte(errMessage))
			return
		}
		buff := new(bytes.Buffer)
		buff.ReadFrom(r.Body)
		var jsonData []byte = nil
		if 0 < buff.Len() {
			jsonData = buff.Bytes()
		}
		if r.Method == "POST" && requestName == string(client_message.CLIENTCONFIGURATION) {
			var clientConfig *client_message.ClientConfigRequest
			err := json.Unmarshal(jsonData, &clientConfig)
			if err != nil {
				log.Errorf("Failed to parse json data : %+v", err)
				return
			}
			mode := clientConfig.SessionConfig.Mode
			log.Debugf("Session config mode: %+v",mode)
			if mode == string(client_message.IDLE) || mode == string(client_message.MITIGATING) {
				log.Debug("Session config mode is valid. Switch to new session config mode")
				env.SetSessionConfigMode(mode)
			} else {
				log.Debug("Session config mode is invalid")
			}
			return
		}
		res, err := sendRequest(jsonData, requestName, r.Method, requestQuerys, env, options)
		if err != nil {
			fmt.Printf("dots_client.serverHandler -- %s", err.Error())
			w.WriteHeader(http.StatusInternalServerError)
			w.Write([]byte(err.Error()))
		}
		w.WriteHeader(res.StatusCode.HttpCode())
		w.Write(res.data)
	}
}