~fnux/yggdrasil-go-coap

3fa5306e2e34c14427872871dcb8ff8aab4f6941 — Jozef Kralik 2 years ago 7043ef4
add Write for satisfy io.Writer interface in ResponseWriter

add validation for Payload,ContentFormat of Msg
M README.md => README.md +4 -6
@@ 32,14 32,12 @@ Fork of https://github.com/dustin/go-coap
	// See /examples/simple/server/main.go
	func handleA(w coap.ResponseWriter, req *coap.Request) {
		log.Printf("Got message in handleA: path=%q: %#v from %v", req.Msg.Path(), req.Msg, req.Client.RemoteAddr())
		resp := w.NewResponse(coap.Content)
		resp.SetOption(coap.ContentFormat, coap.TextPlain)
		resp.SetPayload([]byte("hello world"))
		log.Printf("Transmitting from A %#v", resp)
		if err := w.Write(resp); err != nil {
		w.SetContentFormat(coap.TextPlain)
		log.Printf("Transmitting from A")
		if _, err := w.Write([]byte("hello world")); err != nil {
			log.Printf("Cannot send response: %v", err)
		}
	}	
	}

	func main() {
		mux := coap.NewServeMux()

M blockwise.go => blockwise.go +19 -11
@@ 89,7 89,7 @@ func exchangeDrivedByPeer(session networkSession, req Message, blockType OptionI
		}
		if more == false {
			// we send all datas to peer -> create empty response
			err := session.Write(req)
			err := session.WriteMsg(req)
			if err != nil {
				return nil, err
			}


@@ 106,7 106,7 @@ func exchangeDrivedByPeer(session networkSession, req Message, blockType OptionI
		}
	})
	defer session.TokenHandler().Remove(req.Token())
	err := session.Write(req)
	err := session.WriteMsg(req)
	if err != nil {
		return nil, err
	}


@@ 330,10 330,10 @@ func (b *blockWiseSession) Exchange(msg Message) (Message, error) {

}

func (b *blockWiseSession) Write(msg Message) error {
func (b *blockWiseSession) WriteMsg(msg Message) error {
	switch msg.Code() {
	case CSM, Ping, Pong, Release, Abort, Empty, GET:
		return b.networkSession.Write(msg)
		return b.networkSession.WriteMsg(msg)
	default:
		_, err := b.Exchange(msg)
		return err


@@ 363,7 363,7 @@ func (b *blockWiseSession) sendErrorMsg(code COAPCode, typ COAPType, token []byt
		req.SetOption(ContentFormat, TextPlain)
		req.SetPayload([]byte(err.Error()))
	}
	b.networkSession.Write(req)
	b.networkSession.WriteMsg(req)
}

type blockWiseReceiver struct {


@@ 404,7 404,10 @@ func (r *blockWiseReceiver) createReq(b *blockWiseSession, resp Message) (Messag
	})
	if !r.peerDrive {
		for _, option := range r.origin.AllOptions() {
			req.AddOption(option.ID, option.Value)
			//dont send content format when we receiving payload
			if option.ID != ContentFormat {
				req.AddOption(option.ID, option.Value)
			}
		}
		req.SetMessageID(GenerateMessageID())
	} else if resp == nil {


@@ 702,7 705,9 @@ type blockWiseResponseWriter struct {
	*responseWriter
}

func (w *blockWiseResponseWriter) Write(msg Message) error {
//Write send whole message if size of payload is less then block szx otherwise
//send message via blockwise.
func (w *blockWiseResponseWriter) WriteMsg(msg Message) error {
	suggestedSzx := w.req.Client.networkSession.blockWiseSzx()
	if respBlock2, ok := w.req.Msg.Option(Block2).(uint32); ok {
		szx, _, _, err := UnmarshalBlockOption(respBlock2)


@@ 718,7 723,7 @@ func (w *blockWiseResponseWriter) Write(msg Message) error {

	//resp is less them szx then just write msg without blockWise
	if len(msg.Payload()) < szxToBytes[suggestedSzx] {
		return w.responseWriter.Write(msg)
		return w.responseWriter.WriteMsg(msg)
	}

	if b, ok := w.req.Client.networkSession.(*blockWiseSession); ok {


@@ 733,7 738,10 @@ type blockWiseNoticeWriter struct {
	*responseWriter
}

func (w *blockWiseNoticeWriter) Write(msg Message) error {
//Write send whole message if size of payload is less then block szx otherwise
//send only first block. For Get whole msg client must call Get to
//resource.
func (w *blockWiseNoticeWriter) WriteMsg(msg Message) error {
	suggestedSzx := w.req.Client.networkSession.blockWiseSzx()
	if respBlock2, ok := w.req.Msg.Option(Block2).(uint32); ok {
		szx, _, _, err := UnmarshalBlockOption(respBlock2)


@@ 749,7 757,7 @@ func (w *blockWiseNoticeWriter) Write(msg Message) error {

	//resp is less them szx then just write msg without blockWise
	if len(msg.Payload()) < szxToBytes[suggestedSzx] {
		return w.responseWriter.Write(msg)
		return w.responseWriter.WriteMsg(msg)
	}

	if b, ok := w.req.Client.networkSession.(*blockWiseSession); ok {


@@ 758,7 766,7 @@ func (w *blockWiseNoticeWriter) Write(msg Message) error {
		if err != nil {
			return err
		}
		return b.networkSession.Write(req)
		return b.networkSession.WriteMsg(req)
	}
	return ErrNotSupported
}

M client.go => client.go +10 -10
@@ 260,13 260,13 @@ func (co *ClientConn) NewGetRequest(path string) (Message, error) {
}

// NewPostRequest creates post request
func (co *ClientConn) NewPostRequest(path string, contentType MediaType, body io.Reader) (Message, error) {
	return co.commander.NewPostRequest(path, contentType, body)
func (co *ClientConn) NewPostRequest(path string, contentFormat MediaType, body io.Reader) (Message, error) {
	return co.commander.NewPostRequest(path, contentFormat, body)
}

// NewPutRequest creates put request
func (co *ClientConn) NewPutRequest(path string, contentType MediaType, body io.Reader) (Message, error) {
	return co.commander.NewPutRequest(path, contentType, body)
func (co *ClientConn) NewPutRequest(path string, contentFormat MediaType, body io.Reader) (Message, error) {
	return co.commander.NewPutRequest(path, contentFormat, body)
}

// NewDeleteRequest creates delete request


@@ 275,8 275,8 @@ func (co *ClientConn) NewDeleteRequest(path string) (Message, error) {
}

// Write sends direct a message through the connection
func (co *ClientConn) Write(m Message) error {
	return co.commander.Write(m)
func (co *ClientConn) WriteMsg(m Message) error {
	return co.commander.WriteMsg(m)
}

// SetReadDeadline set read deadline for timeout for Exchange


@@ 303,19 303,19 @@ func (co *ClientConn) Get(path string) (Message, error) {
}

// Post update the resource identified by the request path
func (co *ClientConn) Post(path string, contentType MediaType, body io.Reader) (Message, error) {
func (co *ClientConn) Post(path string, contentFormat MediaType, body io.Reader) (Message, error) {
	if co.multicast {
		return nil, ErrNotSupported
	}
	return co.commander.Post(path, contentType, body)
	return co.commander.Post(path, contentFormat, body)
}

// Put create the resource identified by the request path
func (co *ClientConn) Put(path string, contentType MediaType, body io.Reader) (Message, error) {
func (co *ClientConn) Put(path string, contentFormat MediaType, body io.Reader) (Message, error) {
	if co.multicast {
		return nil, ErrNotSupported
	}
	return co.commander.Put(path, contentType, body)
	return co.commander.Put(path, contentFormat, body)
}

// Delete delete the resource identified by the request path

M client_test.go => client_test.go +7 -7
@@ 21,10 21,10 @@ func periodicTransmitter(w ResponseWriter, r *Request) {
		Token:     r.Msg.Token(),
	})

	//msg.SetOption(ContentFormat, TextPlain)
	msg.SetOption(ContentFormat, TextPlain)
	msg.SetOption(LocationPath, r.Msg.Path())

	err := w.Write(msg)
	err := w.WriteMsg(msg)
	if err != nil {
		log.Printf("Error on transmitter, stopping: %v", err)
		return


@@ 32,7 32,7 @@ func periodicTransmitter(w ResponseWriter, r *Request) {

	go func() {
		time.Sleep(time.Second)
		err := w.Write(msg)
		err := w.WriteMsg(msg)
		if err != nil {
			log.Printf("Error on transmitter, stopping: %v", err)
			return


@@ 70,7 70,7 @@ func testServingObservation(t *testing.T, net string, addrstr string, BlockWiseT
	req.AddOption(Observe, 1)
	req.SetPathString("/some/path")

	err = conn.Write(req)
	err = conn.WriteMsg(req)
	if err != nil {
		t.Fatalf("Error sending request: %v", err)
	}


@@ 154,7 154,7 @@ func testServingMCastByClient(t *testing.T, lnet, laddr string, BlockWiseTransfe
	req.SetOption(ContentFormat, TextPlain)
	req.SetPathString("/test")

	co.Write(req)
	co.WriteMsg(req)

	<-ansArrived
}


@@ 196,7 196,7 @@ func setupServer(t *testing.T) (string, error) {
		msg.SetOption(ContentFormat, TextPlain)
		msg.SetOption(LocationPath, r.Msg.Path())

		err := w.Write(msg)
		err := w.WriteMsg(msg)
		if err != nil {
			t.Fatalf("Error on transmitter, stopping: %v", err)
			return


@@ 298,7 298,7 @@ func TestServingUDPObserve(t *testing.T) {
		msg.SetOption(LocationPath, r.Msg.Path())
		msg.SetOption(Observe, 2)

		err := w.Write(msg)
		err := w.WriteMsg(msg)
		if err != nil {
			t.Fatalf("Error on transmitter, stopping: %v", err)
			return

M clientcommander.go => clientcommander.go +16 -17
@@ 25,7 25,7 @@ func (cc *ClientCommander) newGetDeleteRequest(path string, code COAPCode) (Mess
		return nil, err
	}
	req := cc.NewMessage(MessageParams{
		Type:      NonConfirmable,
		Type:      Confirmable,
		Code:      code,
		MessageID: GenerateMessageID(),
		Token:     token,


@@ 34,7 34,7 @@ func (cc *ClientCommander) newGetDeleteRequest(path string, code COAPCode) (Mess
	return req, nil
}

func (cc *ClientCommander) newPostPutRequest(path string, contentType MediaType, body io.Reader, code COAPCode) (Message, error) {
func (cc *ClientCommander) newPostPutRequest(path string, contentFormat MediaType, body io.Reader, code COAPCode) (Message, error) {
	token, err := GenerateToken()
	if err != nil {
		return nil, err


@@ 46,7 46,7 @@ func (cc *ClientCommander) newPostPutRequest(path string, contentType MediaType,
		Token:     token,
	})
	req.SetPathString(path)
	req.SetOption(ContentFormat, contentType)
	req.SetOption(ContentFormat, contentFormat)
	payload, err := ioutil.ReadAll(body)
	if err != nil {
		return nil, err


@@ 61,13 61,13 @@ func (cc *ClientCommander) NewGetRequest(path string) (Message, error) {
}

// NewPostRequest creates post request
func (cc *ClientCommander) NewPostRequest(path string, contentType MediaType, body io.Reader) (Message, error) {
	return cc.newPostPutRequest(path, contentType, body, POST)
func (cc *ClientCommander) NewPostRequest(path string, contentFormat MediaType, body io.Reader) (Message, error) {
	return cc.newPostPutRequest(path, contentFormat, body, POST)
}

// NewPutRequest creates put request
func (cc *ClientCommander) NewPutRequest(path string, contentType MediaType, body io.Reader) (Message, error) {
	return cc.newPostPutRequest(path, contentType, body, PUT)
func (cc *ClientCommander) NewPutRequest(path string, contentFormat MediaType, body io.Reader) (Message, error) {
	return cc.newPostPutRequest(path, contentFormat, body, PUT)
}

// NewDeleteRequest creates delete request


@@ 101,9 101,9 @@ func (cc *ClientCommander) Exchange(m Message) (Message, error) {
	return cc.networkSession.Exchange(m)
}

// Write sends direct a message through the connection
func (cc *ClientCommander) Write(m Message) error {
	return cc.networkSession.Write(m)
// WriteMsg sends direct a message through the connection
func (cc *ClientCommander) WriteMsg(m Message) error {
	return cc.networkSession.WriteMsg(m)
}

// Ping send a ping message and wait for a pong response


@@ 121,8 121,8 @@ func (cc *ClientCommander) Get(path string) (Message, error) {
}

// Post update the resource identified by the request path
func (cc *ClientCommander) Post(path string, contentType MediaType, body io.Reader) (Message, error) {
	req, err := cc.NewPostRequest(path, contentType, body)
func (cc *ClientCommander) Post(path string, contentFormat MediaType, body io.Reader) (Message, error) {
	req, err := cc.NewPostRequest(path, contentFormat, body)
	if err != nil {
		return nil, err
	}


@@ 130,8 130,8 @@ func (cc *ClientCommander) Post(path string, contentType MediaType, body io.Read
}

// Put create the resource identified by the request path
func (cc *ClientCommander) Put(path string, contentType MediaType, body io.Reader) (Message, error) {
	req, err := cc.NewPutRequest(path, contentType, body)
func (cc *ClientCommander) Put(path string, contentFormat MediaType, body io.Reader) (Message, error) {
	req, err := cc.NewPutRequest(path, contentFormat, body)
	if err != nil {
		return nil, err
	}


@@ 165,7 165,7 @@ func (o *Observation) Cancel() error {
	})
	req.SetPathString(o.path)
	req.SetOption(Observe, 1)
	err1 := o.client.Write(req)
	err1 := o.client.WriteMsg(req)
	err2 := o.client.networkSession.TokenHandler().Remove(o.token)
	if err1 != nil {
		return err1


@@ 212,7 212,6 @@ func (cc *ClientCommander) Observe(path string, observeFunc func(req *Request)) 
					return
				}
				needGet = more

			}
		}



@@ 252,7 251,7 @@ func (cc *ClientCommander) Observe(path string, observeFunc func(req *Request)) 
	if err != nil {
		return nil, err
	}
	err = cc.Write(req)
	err = cc.WriteMsg(req)
	if err != nil {
		cc.networkSession.TokenHandler().Remove(o.token)
		return nil, err

M error.go => error.go +6 -0
@@ 94,3 94,9 @@ const ErrRequestEntityIncomplete = Error("payload comes in bad order")

// ErrInvalidRequest invalid requests
const ErrInvalidRequest = Error("invalid request")

// ErrContentFormatNotSet content format is not set
const ErrContentFormatNotSet = Error("content format is not set")

//ErrInvalidPayload invalid payload
const ErrInvalidPayload = Error("invalid payload")

M examples/mcast/client/main.go => examples/mcast/client/main.go +1 -1
@@ 9,7 9,7 @@ import (
func main() {
	client := &coap.MulticastClient{}

	conn, err := client.Dial("224.0.1.187:5683")
	conn, err := client.Dial("224.0.1.187:5688")
	if err != nil {
		log.Fatalf("Error dialing: %v", err)
	}

M examples/mcast/server/main.go => examples/mcast/server/main.go +3 -5
@@ 8,10 8,8 @@ import (

func handleMcast(w coap.ResponseWriter, r *coap.Request) {
	log.Printf("Got message in handleA: path=%q: %#v from %v", r.Msg.Path(), r.Msg, r.Client.RemoteAddr())
	resp := w.NewResponse(coap.Content)
	resp.SetOption(coap.ContentFormat, coap.TextPlain)
	resp.SetPayload([]byte("hello to you!"))
	if err := w.Write(resp); err != nil {
	w.SetContentFormat(coap.TextPlain)
	if _, err := w.Write([]byte("hello to you!")); err != nil {
		log.Printf("Cannot write resp %v", err)
	}
}


@@ 20,5 18,5 @@ func main() {
	mux := coap.NewServeMux()
	mux.Handle("/oic/res", coap.HandlerFunc(handleMcast))

	log.Fatal(coap.ListenAndServe("224.0.1.187:5683", "udp-mcast", mux))
	log.Fatal(coap.ListenAndServe("224.0.1.187:5688", "udp-mcast", mux))
}

M examples/observe/server/main.go => examples/observe/server/main.go +1 -1
@@ 12,7 12,7 @@ func sendResponse(w coap.ResponseWriter, req *coap.Request, subded time.Time) er
	resp := w.NewResponse(coap.Content)
	resp.SetOption(coap.ContentFormat, coap.TextPlain)
	resp.SetPayload([]byte(fmt.Sprintf("Been running for %v", time.Since(subded))))
	return w.Write(resp)
	return w.WriteMsg(resp)
}

func periodicTransmitter(w coap.ResponseWriter, req *coap.Request) {

M examples/simple/server/main.go => examples/simple/server/main.go +6 -6
@@ 8,11 8,9 @@ import (

func handleA(w coap.ResponseWriter, req *coap.Request) {
	log.Printf("Got message in handleA: path=%q: %#v from %v", req.Msg.Path(), req.Msg, req.Client.RemoteAddr())
	resp := w.NewResponse(coap.Content)
	resp.SetOption(coap.ContentFormat, coap.TextPlain)
	resp.SetPayload([]byte("hello world"))
	log.Printf("Transmitting from A %#v", resp)
	if err := w.Write(resp); err != nil {
	w.SetContentFormat(coap.TextPlain)
	log.Printf("Transmitting from A")
	if _, err := w.Write([]byte("hello world")); err != nil {
		log.Printf("Cannot send response: %v", err)
	}
}


@@ 23,7 21,9 @@ func handleB(w coap.ResponseWriter, req *coap.Request) {
	resp.SetOption(coap.ContentFormat, coap.TextPlain)
	resp.SetPayload([]byte("good bye!"))
	log.Printf("Transmitting from B %#v", resp)
	w.Write(resp)
	if err := w.WriteMsg(resp); err != nil {
		log.Printf("Cannot send response: %v", err)
	}
}

func main() {

M getresponsewriter.go => getresponsewriter.go +4 -4
@@ 1,19 1,19 @@
package coap

type getResponseWriter struct {
	w ResponseWriter
	ResponseWriter
}

// NewResponse creates reponse for request
func (r *getResponseWriter) NewResponse(code COAPCode) Message {
	return r.w.NewResponse(code)
	return r.ResponseWriter.NewResponse(code)
}

// Write send response to peer
func (r *getResponseWriter) Write(msg Message) error {
func (r *getResponseWriter) WriteMsg(msg Message) error {
	if msg.Payload() != nil && msg.Option(ETag) == nil {
		msg.SetOption(ETag, CalcETag(msg.Payload()))
	}

	return r.w.Write(msg)
	return r.ResponseWriter.WriteMsg(msg)
}

M iotivity_test.go => iotivity_test.go +13 -12
@@ 1,17 1,9 @@
package coap

/*
import (
	"bytes"
	"fmt"
	"testing"

	"github.com/ugorji/go/codec"
)

var path = "/oic/d"
var udpServer = "127.0.0.1:49629"
var tcpServer = "127.0.0.1:42635"
var udpServer = "127.0.0.1:52593"
var tcpServer = "127.0.0.1:40993"

func decodeMsg(resp Message) {
	var m interface{}


@@ 88,7 80,17 @@ func TestBlockWiseGetBlock16(t *testing.T) {
	if err != nil {
		t.Fatalf("Error dialing: %v", err)
	}
	resp, err := co.Get(path)
	req, err := co.NewGetRequest(path)
	if err != nil {
		t.Fatalf("Cannot create %v", err)
	}
	block2, err := MarshalBlockOption(BlockWiseSzx16, 0, false)
	if err != nil {
		t.Fatalf("Cannot marshal block %v", err)
	}
	req.SetOption(Block2, block2)
	decodeMsg(req)
	resp, err := co.Exchange(req)
	if err != nil {
		t.Fatalf("Cannot post exchange")
	}


@@ 153,5 155,4 @@ func TestGetBlock16(t *testing.T) {
	}
	decodeMsg(resp)
}

*/

M message.go => message.go +53 -72
@@ 34,6 34,12 @@ var typeNames = [256]string{
	Reset:           "Reset",
}

const (
	max1ByteNumber = uint32(^uint8(0))
	max2ByteNumber = uint32(^uint16(0))
	max3ByteNumber = uint32(0xffffff)
)

func init() {
	for i := range typeNames {
		if typeNames[i] == "" {


@@ 232,10 238,10 @@ var coapOptionDefs = map[OptionID]optionDef{
	Size1:         optionDef{valueFormat: valueUint, minLen: 0, maxLen: 4},
}

// MediaType specifies the content type of a message.
// MediaType specifies the content format of a message.
type MediaType uint16

// Content types.
// Content formats.
const (
	TextPlain         MediaType = 0     // text/plain;charset=utf-8
	AppCoseEncrypt0   MediaType = 16    // application/cose; cose-type="cose-encrypt0" (RFC 8152)


@@ 319,11 325,11 @@ type option struct {
func encodeInt(buf io.Writer, v uint32) error {
	switch {
	case v == 0:
	case v < 256:
	case v <= max1ByteNumber:
		buf.Write([]byte{byte(v)})
	case v < 65536:
	case v <= max2ByteNumber:
		return binary.Write(buf, binary.BigEndian, uint16(v))
	case v < 16777216:
	case v <= max3ByteNumber:
		rv := []byte{0, 0, 0, 0}
		binary.BigEndian.PutUint32(rv, uint32(v))
		_, err := buf.Write(rv[1:])


@@ 338,11 344,11 @@ func lengthInt(v uint32) int {
	switch {
	case v == 0:
		return 0
	case v < 256:
	case v <= max1ByteNumber:
		return 1
	case v < 65536:
	case v <= max2ByteNumber:
		return 2
	case v < 16777216:
	case v <= max3ByteNumber:
		return 3
	default:
		return 4


@@ 677,39 683,18 @@ func writeOpt(o option, buf io.Writer, delta int) {
	   and writeOptionHeader() below for implementation details
	*/

	extendOpt := func(opt int) (int, int) {
		ext := 0
		if opt >= extoptByteAddend {
			if opt >= extoptWordAddend {
				ext = opt - extoptWordAddend
				opt = extoptWordCode
			} else {
				ext = opt - extoptByteAddend
				opt = extoptByteCode
			}
		}
		return opt, ext
	}

	writeOptHeader := func(delta, length int) {
		d, dx := extendOpt(delta)
		l, lx := extendOpt(length)

		//buf.Write([]byte{byte(d<<4) | byte(l)})
		var h [1]byte
		h[0] = byte(d<<4) | byte(l)

		buf.Write(h[:])
		buf.Write([]byte{byte(d<<4) | byte(l)})

		var tmp [2]byte
		writeExt := func(opt, ext int) {
			switch opt {
			case extoptByteCode:
				tmp[0] = byte(ext)
				buf.Write(tmp[:1])
				buf.Write([]byte{byte(ext)})
			case extoptWordCode:
				binary.BigEndian.PutUint16(tmp[:], uint16(ext))
				buf.Write(tmp[:])
				binary.Write(buf, binary.BigEndian, uint16(ext))
			}
		}



@@ 734,6 719,42 @@ func writeOpts(buf io.Writer, opts options) {
	}
}

func extendOpt(opt int) (int, int) {
	ext := 0
	if opt >= extoptByteAddend {
		if opt >= extoptWordAddend {
			ext = opt - extoptWordAddend
			opt = extoptWordCode
		} else {
			ext = opt - extoptByteAddend
			opt = extoptByteCode
		}
	}
	return opt, ext
}

func lengthOptHeaderExt(opt, ext int) int {
	switch opt {
	case extoptByteCode:
		return 1
	case extoptWordCode:
		return 2
	}
	return 0
}

func lengthOptHeader(delta, length int) int {
	d, dx := extendOpt(delta)
	l, lx := extendOpt(length)

	//buf.Write([]byte{byte(d<<4) | byte(l)})
	res := 1

	res = res + lengthOptHeaderExt(d, dx)
	res = res + lengthOptHeaderExt(l, lx)
	return res
}

func lengthOpt(o option, delta int) int {
	/*
	     0   1   2   3   4   5   6   7


@@ 763,46 784,6 @@ func lengthOpt(o option, delta int) int {
	   and writeOptionHeader() below for implementation details
	*/

	extendOpt := func(opt int) (int, int) {
		ext := 0
		if opt >= extoptByteAddend {
			if opt >= extoptWordAddend {
				ext = opt - extoptWordAddend
				opt = extoptWordCode
			} else {
				ext = opt - extoptByteAddend
				opt = extoptByteCode
			}
		}
		return opt, ext
	}

	lengthOptHeader := func(delta, length int) int {
		d, dx := extendOpt(delta)
		l, lx := extendOpt(length)

		//buf.Write([]byte{byte(d<<4) | byte(l)})
		res := 1

		writeExt := func(opt, ext int) int {
			switch opt {
			case extoptByteCode:
				//tmp[0] = byte(ext)
				//buf.Write(tmp[:1])
				return 1
			case extoptWordCode:
				//binary.BigEndian.PutUint16(tmp[:], uint16(ext))
				//buf.Write(tmp[:])
				return 2
			}
			return 0
		}

		res = res + writeExt(d, dx)
		res = res + writeExt(l, lx)
		return res
	}

	res, err := o.toBytesLength()
	if err != nil {
		log.Fatal(err)

M multicastClient.go => multicastClient.go +8 -3
@@ 100,8 100,8 @@ func (mconn *MulticastClientConn) NewGetRequest(path string) (Message, error) {
}

// WriteMsg sends a message through the connection co.
func (mconn *MulticastClientConn) Write(m Message) error {
	return mconn.conn.Write(m)
func (mconn *MulticastClientConn) WriteMsg(m Message) error {
	return mconn.conn.WriteMsg(m)
}

// SetReadDeadline set read deadline for timeout for Exchange


@@ 144,6 144,11 @@ func (mconn *MulticastClientConn) Publish(path string, responseHandler func(req 
		conn:  mconn,
	}
	err = mconn.client.multicastHandler.Add(req.Token(), func(w ResponseWriter, r *Request) {
		switch r.Msg.Code() {
		case GET, POST, PUT, DELETE:
			//dont serve commands by multicast handler (filter own request)
			return
		}
		needGet := false
		resp := r.Msg
		if r.Msg.Option(Size2) != nil {


@@ 173,7 178,7 @@ func (mconn *MulticastClientConn) Publish(path string, responseHandler func(req 
		return nil, err
	}

	err = mconn.Write(req)
	err = mconn.WriteMsg(req)
	if err != nil {
		mconn.client.multicastHandler.Remove(r.token)
		return nil, err

M networksession.go => networksession.go +23 -8
@@ 16,7 16,7 @@ type networkSession interface {
	// RemoteAddr returns the net.Addr of the client that sent the current request.
	RemoteAddr() net.Addr
	// WriteMsg writes a reply back to the client.
	Write(resp Message) error
	WriteMsg(resp Message) error
	// Close closes the connection.
	Close() error
	// Return type of network


@@ 421,22 421,37 @@ func (s *sessionUDP) exchangeTimeout(req Message, writeDeadline, readDeadline ti
}

// Write implements the networkSession.Write method.
func (s *sessionTCP) Write(m Message) error {
func (s *sessionTCP) WriteMsg(m Message) error {
	return s.writeTimeout(m, s.writeDeadline)
}

func (s *sessionUDP) Write(m Message) error {
func (s *sessionUDP) WriteMsg(m Message) error {
	return s.writeTimeout(m, s.writeDeadline)
}

func (s *sessionTCP) writeTimeout(m Message, timeout time.Duration) error {
func validateMsg(msg Message) error {
	if msg.Payload() != nil && msg.Option(ContentFormat) == nil {
		return ErrContentFormatNotSet
	}
	if msg.Payload() == nil && msg.Option(ContentFormat) != nil {
		return ErrInvalidPayload
	}
	//TODO check size of m
	return nil
}

func (s *sessionTCP) writeTimeout(m Message, timeout time.Duration) error {
	if err := validateMsg(m); err != nil {
		return err
	}
	return s.connection.write(&writeReqTCP{writeReqBase{req: m, respChan: make(chan error, 1)}}, timeout)
}

// WriteMsg implements the networkSession.WriteMsg method.
func (s *sessionUDP) writeTimeout(m Message, timeout time.Duration) error {
	//TODO check size of m
	if err := validateMsg(m); err != nil {
		return err
	}
	return s.connection.write(&writeReqUDP{writeReqBase{req: m, respChan: make(chan error, 1)}, s.sessionUDPData}, timeout)
}



@@ 491,7 506,7 @@ func (s *sessionTCP) sendCSM() error {
	if s.blockWiseEnabled() {
		req.AddOption(BlockWiseTransfer, []byte{})
	}
	return s.Write(req)
	return s.WriteMsg(req)
}

func (s *sessionTCP) setPeerMaxMessageSize(val uint32) {


@@ 512,7 527,7 @@ func (s *sessionUDP) sendPong(w ResponseWriter, r *Request) error {
		Code:      Empty,
		MessageID: r.Msg.MessageID(),
	})
	return w.Write(resp)
	return w.WriteMsg(resp)
}

func (s *sessionTCP) sendPong(w ResponseWriter, r *Request) error {


@@ 521,7 536,7 @@ func (s *sessionTCP) sendPong(w ResponseWriter, r *Request) error {
		Code:  Pong,
		Token: r.Msg.Token(),
	})
	return w.Write(req)
	return w.WriteMsg(req)
}

func (s *sessionTCP) handleSignals(w ResponseWriter, r *Request) bool {

M responsewriter.go => responsewriter.go +63 -5
@@ 1,13 1,37 @@
package coap

//A ResponseWriter interface is used by an CAOP handler to construct an COAP response.
// A ResponseWriter interface is used by an CAOP handler to construct an COAP response.
// For Obsevation (GET+option observe) it can be stored and used in another go-routine
// with using calls NewResponse, WriteMsg
type ResponseWriter interface {
	Write(Message) error
	// Write response with payload.
	// If p is nil it writes response without payload.
	// If p is non-nil then SetContentFormat must be called before Write otherwise Write fails.
	Write(p []byte) (n int, err error)
	// SetCode for response that is send via Write call.
	//
	// If SetCode is not called explicitly, the first call to Write
	// will trigger an implicit SetCode(Content/Changed/Deleted/Created - depends on request).
	// Thus explicit calls to SetCode are mainly used to send error codes.
	SetCode(code COAPCode)
	// SetContentFormat of payload for response that is send via Write call.
	//
	// If SetContentFormat is not called and Write is called with non-nil argumet
	// If SetContentFormat is set but Write is called with nil argument it fails
	SetContentFormat(contentFormat MediaType)

	//NewResponse create response with code and token, messageid against request
	NewResponse(code COAPCode) Message
	//WriteMsg to client.
	//If Option ContentFormat is set and Payload is not set then call will failed.
	//If Option ContentFormat is not set and Payload is set then call will failed.
	WriteMsg(Message) error
}

type responseWriter struct {
	req *Request
	req           *Request
	code          *COAPCode
	contentFormat *MediaType
}

// NewResponse creates reponse for request


@@ 26,10 50,44 @@ func (r *responseWriter) NewResponse(code COAPCode) Message {
}

// Write send response to peer
func (r *responseWriter) Write(msg Message) error {
func (r *responseWriter) WriteMsg(msg Message) error {
	switch msg.Code() {
	case GET, POST, PUT, DELETE:
		return ErrInvalidReponseCode
	}
	return r.req.Client.Write(msg)
	return r.req.Client.WriteMsg(msg)
}

// Write send response to peer
func (r *responseWriter) Write(p []byte) (n int, err error) {
	code := Content
	if r.code != nil {
		code = *r.code
	} else {
		switch r.req.Msg.Code() {
		case POST:
			code = Changed
		case PUT:
			code = Created
		case DELETE:
			code = Deleted
		}
	}
	resp := r.NewResponse(code)
	if r.contentFormat != nil {
		resp.SetOption(ContentFormat, *r.contentFormat)
	}
	if p != nil {
		resp.SetPayload(p)
	}
	err = r.WriteMsg(resp)
	return len(p), err
}

func (r *responseWriter) SetCode(code COAPCode) {
	r.code = &code
}

func (r *responseWriter) SetContentFormat(contentFormat MediaType) {
	r.contentFormat = &contentFormat
}

M server.go => server.go +1 -1
@@ 55,7 55,7 @@ func HandleFailed(w ResponseWriter, req *Request) {
		MessageID: req.Msg.MessageID(),
		Token:     req.Msg.Token(),
	})
	w.Write(msg)
	w.WriteMsg(msg)
}

func failedHandler() Handler { return HandlerFunc(HandleFailed) }

M server_test.go => server_test.go +30 -11
@@ 45,7 45,7 @@ func CreateRespMessageByReq(isTCP bool, code COAPCode, req Message) Message {

func EchoServer(w ResponseWriter, r *Request) {
	if r.Msg.IsConfirmable() {
		err := w.Write(CreateRespMessageByReq(r.Client.networkSession.IsTCP(), Valid, r.Msg))
		err := w.WriteMsg(CreateRespMessageByReq(r.Client.networkSession.IsTCP(), Valid, r.Msg))
		if err != nil {
			log.Printf("Cannot write echo %v", err)
		}


@@ 54,7 54,7 @@ func EchoServer(w ResponseWriter, r *Request) {

func EchoServerBadID(w ResponseWriter, r *Request) {
	if r.Msg.IsConfirmable() {
		w.Write(CreateRespMessageByReq(r.Client.networkSession.IsTCP(), BadRequest, r.Msg))
		w.WriteMsg(CreateRespMessageByReq(r.Client.networkSession.IsTCP(), BadRequest, r.Msg))
	}
}



@@ 299,7 299,7 @@ func ChallegingServer(w ResponseWriter, r *Request) {
		panic(err.Error())
	}

	w.Write(CreateRespMessageByReq(r.Client.networkSession.IsTCP(), Valid, r.Msg))
	w.WriteMsg(CreateRespMessageByReq(r.Client.networkSession.IsTCP(), Valid, r.Msg))
}

func ChallegingServerTimeout(w ResponseWriter, r *Request) {


@@ 316,7 316,7 @@ func ChallegingServerTimeout(w ResponseWriter, r *Request) {
		panic("Error: expected timeout")
	}

	w.Write(CreateRespMessageByReq(r.Client.networkSession.IsTCP(), Valid, r.Msg))
	w.WriteMsg(CreateRespMessageByReq(r.Client.networkSession.IsTCP(), Valid, r.Msg))
}

func simpleChallengingMsg(t *testing.T, payload []byte, co *ClientConn) {


@@ 406,7 406,7 @@ func testServingMCast(t *testing.T, lnet, laddr string, BlockWiseTransfer bool, 
		Handler: func(w ResponseWriter, r *Request) {
			resp := w.NewResponse(Content)
			resp.SetPayload(make([]byte, payloadLen))
			err := w.Write(resp)
			err := w.WriteMsg(resp)
			if err != nil {
				t.Fatalf("cannot send response %v", err)
			}


@@ 416,11 416,12 @@ func testServingMCast(t *testing.T, lnet, laddr string, BlockWiseTransfer bool, 
	s, _, fin, err := RunLocalServerUDPWithHandler(lnet, addrMcast, BlockWiseTransfer, BlockWiseTransferSzx, func(w ResponseWriter, r *Request) {
		resp := w.NewResponse(Content)
		resp.SetPayload(make([]byte, payloadLen))
		resp.SetOption(ContentFormat, TextPlain)
		conn, err := responseServer.Dial(r.Client.RemoteAddr().String())
		if err != nil {
			t.Fatalf("cannot create connection %v", err)
		}
		err = conn.Write(resp)
		err = conn.WriteMsg(resp)
		if err != nil {
			t.Fatalf("cannot send response %v", err)
		}


@@ 496,7 497,10 @@ func BenchmarkServe(b *testing.B) {
	HandleFunc("/test", EchoServer)
	defer HandleRemove("/test")

	s, addrstr, fin, err := RunLocalUDPServer("udp", ":0", false, BlockWiseSzx16)
	BlockWiseTransfer := false
	BlockWiseTransferSzx := BlockWiseSzx1024

	s, addrstr, fin, err := RunLocalUDPServer("udp", ":0", BlockWiseTransfer, BlockWiseTransferSzx)
	if err != nil {
		b.Fatalf("unable to run test server: %v", err)
	}


@@ 505,7 509,13 @@ func BenchmarkServe(b *testing.B) {
		<-fin
	}()

	co, err := Dial("udp", addrstr)
	client := Client{
		Net:                  "udp",
		BlockWiseTransfer:    &BlockWiseTransfer,
		BlockWiseTransferSzx: &BlockWiseTransferSzx,
		MaxMessageSize:       ^uint32(0),
	}
	co, err := client.Dial(addrstr)
	if err != nil {
		b.Fatalf("unable to dialing: %v", err)
	}


@@ 526,7 536,10 @@ func BenchmarkServeBlockWise(b *testing.B) {
	HandleFunc("/test", EchoServer)
	defer HandleRemove("/test")

	s, addrstr, fin, err := RunLocalUDPServer("udp", ":0", true, BlockWiseSzx1024)
	BlockWiseTransfer := true
	BlockWiseTransferSzx := BlockWiseSzx16

	s, addrstr, fin, err := RunLocalUDPServer("udp", ":0", BlockWiseTransfer, BlockWiseSzx1024)
	if err != nil {
		b.Fatalf("unable to run test server: %v", err)
	}


@@ 535,13 548,19 @@ func BenchmarkServeBlockWise(b *testing.B) {
		<-fin
	}()

	co, err := Dial("udp", addrstr)
	client := Client{
		Net:                  "udp",
		BlockWiseTransfer:    &BlockWiseTransfer,
		BlockWiseTransferSzx: &BlockWiseTransferSzx,
		MaxMessageSize:       ^uint32(0),
	}
	co, err := client.Dial(addrstr)
	if err != nil {
		b.Fatalf("unable to dialing: %v", err)
	}
	defer co.Close()

	data := make([]byte, ^uint16(0))
	data := make([]byte, 128)
	b.StartTimer()
	for i := uint32(0); i < uint32(b.N); i++ {
		_, err := co.Post("/test", TextPlain, &dataReader{data: data})