1/* 2 * Copyright (C) Max Romanov 3 * Copyright (C) NGINX, Inc. 4 */ 5 6package unit 7 8/* 9#include "nxt_cgo_lib.h" 10*/ 11import "C" 12 13import ( 14 "fmt" 15 "net/http" 16 "sync" 17 "unsafe" 18) 19 20type cbuf struct { 21 b C.uintptr_t 22 s C.size_t 23} 24 25func buf_ref(buf []byte) C.uintptr_t { 26 if len(buf) == 0 { 27 return 0 28 } 29 30 return C.uintptr_t(uintptr(unsafe.Pointer(&buf[0]))) 31} 32 33type string_header struct { 34 Data unsafe.Pointer 35 Len int 36} 37 38func str_ref(s string) *C.char { 39 header := (*string_header)(unsafe.Pointer(&s)) 40 41 return (*C.char)(header.Data) 42} 43 44func (buf *cbuf) init_bytes(b []byte) { 45 buf.b = buf_ref(b) 46 buf.s = C.size_t(len(b)) 47} 48 49type slice_header struct { 50 Data unsafe.Pointer 51 Len int 52 Cap int 53} 54 55func (buf *cbuf) GoBytes() []byte { 56 if buf == nil { 57 var b [0]byte 58 return b[:0] 59 } 60 61 header := &slice_header{ 62 Data: unsafe.Pointer(uintptr(buf.b)), 63 Len: int(buf.s), 64 Cap: int(buf.s), 65 } 66 67 return *(*[]byte)(unsafe.Pointer(header)) 68} 69 70func GoBytes(buf unsafe.Pointer, size C.int) []byte { 71 bytesHeader := &slice_header{ 72 Data: buf, 73 Len: int(size), 74 Cap: int(size), 75 } 76 77 return *(*[]byte)(unsafe.Pointer(bytesHeader)) 78} 79 80func GoStringN(sptr *C.nxt_unit_sptr_t, l C.int) string { 81 p := unsafe.Pointer(sptr) 82 b := uintptr(p) + uintptr(*(*C.uint32_t)(p)) 83 84 return C.GoStringN((*C.char)(unsafe.Pointer(b)), l) 85} 86 87func nxt_go_warn(format string, args ...interface{}) { 88 str := fmt.Sprintf("[go] " + format, args...) 89 90 C.nxt_cgo_warn(str_ref(str), C.uint32_t(len(str))) 91} 92 93func nxt_go_alert(format string, args ...interface{}) { 94 str := fmt.Sprintf("[go] " + format, args...) 95 96 C.nxt_cgo_alert(str_ref(str), C.uint32_t(len(str))) 97} 98 99type handler_registry struct { 100 sync.RWMutex 101 next uintptr 102 m map[uintptr]*http.Handler 103} 104 105var handler_registry_ handler_registry 106 107func set_handler(handler *http.Handler) uintptr { 108 109 handler_registry_.Lock() 110 if handler_registry_.m == nil { 111 handler_registry_.m = make(map[uintptr]*http.Handler) 112 handler_registry_.next = 1 113 } 114 115 h := handler_registry_.next 116 handler_registry_.next += 1 117 handler_registry_.m[h] = handler 118 119 handler_registry_.Unlock() 120 121 return h 122} 123 124func get_handler(h uintptr) http.Handler { 125 handler_registry_.RLock() 126 defer handler_registry_.RUnlock() 127 128 return *handler_registry_.m[h] 129} 130 131func reset_handler(h uintptr) { 132 133 handler_registry_.Lock() 134 if handler_registry_.m != nil { 135 delete(handler_registry_.m, h) 136 } 137 138 handler_registry_.Unlock() 139} 140 141func ListenAndServe(addr string, handler http.Handler) error { 142 if handler == nil { 143 handler = http.DefaultServeMux 144 } 145 146 h := set_handler(&handler) 147 148 rc := C.nxt_cgo_run(C.uintptr_t(h)) 149 150 reset_handler(h) 151 152 if rc != 0 { 153 return http.ListenAndServe(addr, handler) 154 } 155 156 return nil 157} 158