~fnux/yggdrasil-go-coap

yggdrasil-go-coap/noresponsewriter.go -rw-r--r-- 2.5 KiB
614f652bTimothée Floure Add syntax highlighting to code snippets in README 1 year, 6 months ago
                                                                                
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
package coap

import "context"

var (
	resp2XXCodes = []COAPCode{Created, Deleted, Valid, Changed, Content}
	resp4XXCodes = []COAPCode{BadRequest, Unauthorized, BadOption, Forbidden, NotFound, MethodNotAllowed, NotAcceptable, PreconditionFailed, RequestEntityTooLarge, UnsupportedMediaType}
	resp5XXCodes = []COAPCode{InternalServerError, NotImplemented, BadGateway, ServiceUnavailable, GatewayTimeout, ProxyingNotSupported}
)

func isSet(n uint32, pos uint32) bool {
	val := n & (1 << pos)
	return (val > 0)
}

func powerOfTwo(exponent uint32) uint32 {
	if exponent != 0 {
		return (2 * powerOfTwo(exponent-1))
	}
	return 1
}

func (w *noResponseWriter) decodeNoResponseOption(v uint32) []COAPCode {
	var codes []COAPCode
	if v == 0 {
		// No suppresed code
		return codes
	}

	var i uint32
	// Max bit value:4; ref:table_2_rfc7967
	for i = 0; i <= 4; i++ {
		if isSet(v, i) {
			index := powerOfTwo(i)
			codes = append(codes, w.noResponseValueMap[index]...)
		}
	}
	return codes
}

type noResponseWriter struct {
	ResponseWriter
	noResponseValueMap map[uint32][]COAPCode
}

func newNoResponseWriter(w ResponseWriter) *noResponseWriter {
	return &noResponseWriter{
		ResponseWriter: w,
		noResponseValueMap: map[uint32][]COAPCode{
			2:  resp2XXCodes,
			8:  resp4XXCodes,
			16: resp5XXCodes,
		},
	}
}

func (w *noResponseWriter) Write(p []byte) (n int, err error) {
	return w.WriteWithContext(context.Background(), p)
}

func (w *noResponseWriter) WriteWithContext(ctx context.Context, p []byte) (n int, err error) {
	l, resp := prepareReponse(w, w.ResponseWriter.getReq().Msg.Code(), w.ResponseWriter.getCode(), w.ResponseWriter.getContentFormat(), p)
	err = w.WriteMsgWithContext(ctx, resp)
	return l, err
}

func (w *noResponseWriter) SetCode(code COAPCode) {
	w.ResponseWriter.SetCode(code)
}

func (w *noResponseWriter) SetContentFormat(contentFormat MediaType) {
	w.ResponseWriter.SetContentFormat(contentFormat)
}

func (w *noResponseWriter) NewResponse(code COAPCode) Message {
	return w.ResponseWriter.NewResponse(code)
}

func (w *noResponseWriter) WriteMsg(msg Message) error {
	return w.WriteMsgWithContext(context.Background(), msg)
}

func (w *noResponseWriter) WriteMsgWithContext(ctx context.Context, msg Message) error {
	noRespValue, ok := w.ResponseWriter.getReq().Msg.Option(NoResponse).(uint32)
	if !ok {
		return ErrNotSupported
	}
	suppressedCodes := w.decodeNoResponseOption(noRespValue)

	for _, code := range suppressedCodes {
		if code == msg.Code() {
			return ErrMessageNotInterested
		}
	}
	return w.ResponseWriter.getReq().Client.WriteMsgWithContext(ctx, msg)
}