Merge pull request #63 from YorikSar/streams
Add streams support to libvirt RPC API
This commit is contained in:
		
							
								
								
									
										1
									
								
								AUTHORS
									
									
									
									
									
								
							
							
						
						
									
										1
									
								
								AUTHORS
									
									
									
									
									
								
							| @@ -17,3 +17,4 @@ Simarpreet Singh <simar@linux.com> | ||||
| Alexander Polyakov <apolyakov@beget.com> | ||||
| Amanda Andrade <amanda.andrade@serpro.gov.br> | ||||
| Geoff Hickey <ghickey@digitalocean.com> | ||||
| Yuriy Taraday <yorik.sar@gmail.com> | ||||
|   | ||||
| @@ -159,13 +159,21 @@ type Case struct { | ||||
|  | ||||
| // Proc holds information about a libvirt procedure the parser has found. | ||||
| type Proc struct { | ||||
| 	Num        int64  // The libvirt procedure number. | ||||
| 	Name       string // The name of the go func. | ||||
| 	LVName     string // The name of the libvirt proc this wraps. | ||||
| 	Args       []Decl // The contents of the args struct for this procedure. | ||||
| 	Ret        []Decl // The contents of the ret struct for this procedure. | ||||
| 	ArgsStruct string // The name of the args struct for this procedure. | ||||
| 	RetStruct  string // The name of the ret struct for this procedure. | ||||
| 	Num            int64  // The libvirt procedure number. | ||||
| 	Name           string // The name of the go func. | ||||
| 	LVName         string // The name of the libvirt proc this wraps. | ||||
| 	Args           []Decl // The contents of the args struct for this procedure. | ||||
| 	Ret            []Decl // The contents of the ret struct for this procedure. | ||||
| 	ArgsStruct     string // The name of the args struct for this procedure. | ||||
| 	RetStruct      string // The name of the ret struct for this procedure. | ||||
| 	ReadStreamIdx  int    // The index of read stream in function argument list | ||||
| 	WriteStreamIdx int    // The index of read stream in function argument list | ||||
| } | ||||
|  | ||||
| // ProcMeta holds information from annotations attached to a libvirt procedure | ||||
| type ProcMeta struct { | ||||
| 	ReadStream  int | ||||
| 	WriteStream int | ||||
| } | ||||
|  | ||||
| type structStack []*Structure | ||||
| @@ -552,7 +560,31 @@ func AddEnumVal(name, val string) error { | ||||
| 	if err != nil { | ||||
| 		return fmt.Errorf("invalid enum value %v = %v", name, val) | ||||
| 	} | ||||
| 	return addEnumVal(name, ev) | ||||
| 	return addEnumVal(name, ev, nil) | ||||
| } | ||||
|  | ||||
| // AddEnumValMeta will add a new enum value with attached metadata to the list. | ||||
| // Metadata is parsed from annotations in libvirt RPC description file that are | ||||
| // in block comment preceding every function in enum, it looks like this: | ||||
| // /** | ||||
| //  * @generate: both | ||||
| //  * @readstream: 1 | ||||
| //  * @sparseflag: VIR_STORAGE_VOL_DOWNLOAD_SPARSE_STREAM | ||||
| //  * @acl: storage_vol:data_read | ||||
| //  */ | ||||
| // See full description of possible annotations in libvirt's src/remote/remote_protocol.x | ||||
| // at the top of remote_procedure enum. | ||||
| // We're parsing only @readstream and @writestream annotations at the moment. | ||||
| func AddEnumValMeta(name, val, meta string) error { | ||||
| 	ev, err := parseNumber(val) | ||||
| 	if err != nil { | ||||
| 		return fmt.Errorf("invalid enum value %v = %v", name, val) | ||||
| 	} | ||||
| 	metaObj, err := parseMeta(meta) | ||||
| 	if err != nil { | ||||
| 		return fmt.Errorf("invalid metadata for enum value %v: %v", name, err) | ||||
| 	} | ||||
| 	return addEnumVal(name, ev, metaObj) | ||||
| } | ||||
|  | ||||
| // AddEnumAutoVal adds an enum to the list, using the automatically-incremented | ||||
| @@ -560,14 +592,14 @@ func AddEnumVal(name, val string) error { | ||||
| // explicit value. | ||||
| func AddEnumAutoVal(name string) error { | ||||
| 	CurrentEnumVal++ | ||||
| 	return addEnumVal(name, CurrentEnumVal) | ||||
| 	return addEnumVal(name, CurrentEnumVal, nil) | ||||
| } | ||||
|  | ||||
| func addEnumVal(name string, val int64) error { | ||||
| func addEnumVal(name string, val int64, meta *ProcMeta) error { | ||||
| 	goname := constNameTransform(name) | ||||
| 	Gen.EnumVals = append(Gen.EnumVals, ConstItem{goname, name, fmt.Sprintf("%d", val)}) | ||||
| 	CurrentEnumVal = val | ||||
| 	addProc(goname, name, val) | ||||
| 	addProc(goname, name, val, meta) | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| @@ -584,12 +616,16 @@ func AddConst(name, val string) error { | ||||
|  | ||||
| // addProc checks an enum value to see if it's a procedure number. If so, we | ||||
| // add the procedure to our list for later generation. | ||||
| func addProc(goname, lvname string, val int64) { | ||||
| func addProc(goname, lvname string, val int64, meta *ProcMeta) { | ||||
| 	if !strings.HasPrefix(goname, "Proc") { | ||||
| 		return | ||||
| 	} | ||||
| 	goname = goname[4:] | ||||
| 	proc := &Proc{Num: val, Name: goname, LVName: lvname} | ||||
| 	proc := &Proc{Num: val, Name: goname, LVName: lvname, ReadStreamIdx: -1, WriteStreamIdx: -1} | ||||
| 	if meta != nil { | ||||
| 		proc.ReadStreamIdx = meta.ReadStream | ||||
| 		proc.WriteStreamIdx = meta.WriteStream | ||||
| 	} | ||||
| 	Gen.Procs = append(Gen.Procs, *proc) | ||||
| } | ||||
|  | ||||
| @@ -605,6 +641,41 @@ func parseNumber(val string) (int64, error) { | ||||
| 	return n, err | ||||
| } | ||||
|  | ||||
| // parseMeta parses procedure metadata to simple string mapping | ||||
| func parseMeta(meta string) (*ProcMeta, error) { | ||||
| 	res := &ProcMeta{ | ||||
| 		ReadStream:  -1, | ||||
| 		WriteStream: -1, | ||||
| 	} | ||||
| 	for _, line := range strings.Split(meta, "\n") { | ||||
| 		atInd := strings.Index(line, "@") | ||||
| 		if atInd == -1 { | ||||
| 			// Should be only first and last line of comment | ||||
| 			continue | ||||
| 		} | ||||
| 		spl := strings.SplitN(line[atInd+1:], ":", 2) | ||||
| 		if len(spl) != 2 { | ||||
| 			return nil, fmt.Errorf("invalid annotation: %s", meta) | ||||
| 		} | ||||
| 		spl[1] = strings.Trim(spl[1], " ") | ||||
| 		switch spl[0] { | ||||
| 		case "readstream": | ||||
| 			var err error | ||||
| 			res.ReadStream, err = strconv.Atoi(spl[1]) | ||||
| 			if err != nil { | ||||
| 				return nil, fmt.Errorf("invalid value for readstream: %s", spl[1]) | ||||
| 			} | ||||
| 		case "writestream": | ||||
| 			var err error | ||||
| 			res.WriteStream, err = strconv.Atoi(spl[1]) | ||||
| 			if err != nil { | ||||
| 				return nil, fmt.Errorf("invalid value for writestream: %s", spl[1]) | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| 	return res, nil | ||||
| } | ||||
|  | ||||
| // StartStruct is called from the parser when a struct definition is found, but | ||||
| // before the member declarations are processed. | ||||
| func StartStruct(name string) { | ||||
|   | ||||
| @@ -259,12 +259,19 @@ func lexText(l *Lexer) stateFn { | ||||
|  | ||||
| // lexBlockComment is used when we find a comment marker '/*' in the input. | ||||
| func lexBlockComment(l *Lexer) stateFn { | ||||
| 	// Double star is used only at the start of metadata comments | ||||
| 	metadataComment := strings.HasPrefix(l.input[l.pos:], "/**") | ||||
| 	for { | ||||
| 		if strings.HasPrefix(l.input[l.pos:], "*/") { | ||||
| 			// Found the end. Advance past the '*/' and discard the comment body. | ||||
| 			// Found the end. Advance past the '*/' and discard the comment body | ||||
| 			// unless it's a metadata comment | ||||
| 			l.next() | ||||
| 			l.next() | ||||
| 			l.ignore() | ||||
| 			if metadataComment { | ||||
| 				l.emit(METADATACOMMENT) | ||||
| 			} else { | ||||
| 				l.ignore() | ||||
| 			} | ||||
| 			return lexText | ||||
| 		} | ||||
| 		if l.next() == eof { | ||||
|   | ||||
| @@ -23,6 +23,7 @@ package libvirt | ||||
| import ( | ||||
| 	"bytes" | ||||
| 	"fmt" | ||||
| 	"io" | ||||
|  | ||||
| 	"github.com/davecgh/go-xdr/xdr2" | ||||
| 	"github.com/digitalocean/go-libvirt/internal/constants" | ||||
| @@ -126,9 +127,15 @@ func decodeTypedParams(dec *xdr.Decoder) ([]TypedParam, error) { | ||||
| 	return params, nil | ||||
| } | ||||
|  | ||||
| {{range .Procs}} | ||||
| {{range $proc := .Procs}} | ||||
| // {{.Name}} is the go wrapper for {{.LVName}}. | ||||
| func (l *Libvirt) {{.Name}}({{range $ix, $arg := .Args}}{{if $ix}}, {{end}}{{.Name}} {{.Type}}{{end}}) ({{range .Ret}}r{{.Name}} {{.Type}}, {{end}}err error) { | ||||
| func (l *Libvirt) {{.Name}}( | ||||
|   {{- range $ix, $arg := .Args}} | ||||
|     {{- if (eq $ix $proc.WriteStreamIdx)}}{{if $ix}}, {{end}}outStream io.Reader{{end}} | ||||
|     {{- if (eq $ix $proc.ReadStreamIdx)}}{{if $ix}}, {{end}}inStream io.Writer{{end}} | ||||
|     {{- if $ix}}, {{end}}{{.Name}} {{.Type}} | ||||
|   {{- end -}} | ||||
| ) ({{range .Ret}}r{{.Name}} {{.Type}}, {{end}}err error) { | ||||
| 	var buf []byte | ||||
| {{if .ArgsStruct}} | ||||
| 	args := {{.ArgsStruct}} { | ||||
| @@ -141,7 +148,10 @@ func (l *Libvirt) {{.Name}}({{range $ix, $arg := .Args}}{{if $ix}}, {{end}}{{.Na | ||||
| 	} | ||||
| {{end}} | ||||
| {{if .RetStruct}}	var r response{{end}} | ||||
| 	{{if .RetStruct}}r{{else}}_{{end}}, err = l.request({{.Num}}, constants.Program, buf) | ||||
| 	{{if .RetStruct}}r{{else}}_{{end}}, err = l.requestStream({{.Num}}, constants.Program, buf, | ||||
|     {{- if (ne .WriteStreamIdx -1)}} outStream,{{else}} nil,{{end}} | ||||
|     {{- if (ne .ReadStreamIdx -1)}} inStream{{else}} nil{{end -}} | ||||
|     ) | ||||
| 	if err != nil { | ||||
| 		return | ||||
| 	} | ||||
|   | ||||
| @@ -56,6 +56,7 @@ import ( | ||||
| %token IDENTIFIER CONSTANT ERROR | ||||
| // RPCL additional tokens: | ||||
| %token PROGRAM VERSION | ||||
| %token METADATACOMMENT | ||||
|  | ||||
| %% | ||||
|  | ||||
| @@ -99,6 +100,13 @@ enum_value | ||||
|             return 1 | ||||
|         } | ||||
|     } | ||||
|     | METADATACOMMENT enum_value_ident '=' value { | ||||
|         err := AddEnumValMeta($2.val, $4.val, $1.val) | ||||
|         if err != nil { | ||||
|             yylex.Error(err.Error()) | ||||
|             return 1 | ||||
|         } | ||||
|     } | ||||
|     | enum_value_ident '=' value { | ||||
|         err := AddEnumVal($1.val, $3.val) | ||||
|         if err != nil { | ||||
|   | ||||
| @@ -59,6 +59,7 @@ const CONSTANT = 57366 | ||||
| const ERROR = 57367 | ||||
| const PROGRAM = 57368 | ||||
| const VERSION = 57369 | ||||
| const METADATACOMMENT = 57370 | ||||
|  | ||||
| var yyToknames = [...]string{ | ||||
| 	"$end", | ||||
| @@ -88,6 +89,7 @@ var yyToknames = [...]string{ | ||||
| 	"ERROR", | ||||
| 	"PROGRAM", | ||||
| 	"VERSION", | ||||
| 	"METADATACOMMENT", | ||||
| 	"';'", | ||||
| 	"'{'", | ||||
| 	"'}'", | ||||
| @@ -108,7 +110,7 @@ const yyEofCode = 1 | ||||
| const yyErrCode = 2 | ||||
| const yyInitialStackSize = 16 | ||||
|  | ||||
| //line sunrpc.y:259 | ||||
| //line sunrpc.y:267 | ||||
|  | ||||
| //line yacctab:1 | ||||
| var yyExca = [...]int{ | ||||
| @@ -119,106 +121,107 @@ var yyExca = [...]int{ | ||||
|  | ||||
| const yyPrivate = 57344 | ||||
|  | ||||
| const yyLast = 148 | ||||
| const yyLast = 153 | ||||
|  | ||||
| var yyAct = [...]int{ | ||||
|  | ||||
| 	84, 77, 36, 111, 103, 76, 61, 67, 32, 129, | ||||
| 	55, 126, 128, 100, 37, 117, 85, 86, 78, 63, | ||||
| 	98, 97, 73, 31, 74, 69, 131, 115, 71, 89, | ||||
| 	41, 94, 72, 62, 40, 10, 39, 43, 42, 13, | ||||
| 	30, 118, 14, 38, 107, 48, 49, 50, 51, 47, | ||||
| 	90, 11, 79, 64, 10, 70, 106, 96, 13, 54, | ||||
| 	12, 14, 52, 29, 134, 127, 119, 108, 91, 75, | ||||
| 	80, 15, 16, 110, 87, 88, 85, 86, 59, 60, | ||||
| 	63, 93, 83, 48, 49, 50, 51, 92, 95, 58, | ||||
| 	82, 27, 25, 23, 20, 102, 18, 99, 2, 105, | ||||
| 	101, 46, 8, 66, 45, 7, 109, 44, 4, 104, | ||||
| 	113, 105, 114, 116, 120, 28, 122, 81, 8, 68, | ||||
| 	123, 7, 26, 124, 4, 121, 125, 112, 130, 53, | ||||
| 	24, 132, 133, 65, 22, 35, 34, 33, 21, 19, | ||||
| 	57, 56, 17, 9, 6, 5, 3, 1, | ||||
| 	86, 79, 36, 115, 107, 78, 62, 32, 68, 55, | ||||
| 	57, 133, 130, 132, 104, 121, 87, 88, 80, 64, | ||||
| 	37, 102, 75, 31, 76, 101, 114, 135, 119, 72, | ||||
| 	92, 41, 97, 89, 63, 40, 10, 39, 43, 42, | ||||
| 	13, 73, 30, 14, 38, 122, 48, 49, 50, 51, | ||||
| 	47, 111, 93, 81, 71, 11, 110, 138, 10, 65, | ||||
| 	99, 54, 13, 52, 12, 14, 29, 131, 123, 74, | ||||
| 	77, 112, 94, 59, 82, 15, 90, 91, 58, 70, | ||||
| 	16, 64, 85, 96, 87, 88, 60, 61, 95, 84, | ||||
| 	100, 98, 48, 49, 50, 51, 113, 59, 106, 27, | ||||
| 	103, 25, 109, 105, 23, 20, 18, 67, 46, 8, | ||||
| 	108, 45, 7, 44, 4, 109, 2, 120, 124, 117, | ||||
| 	126, 118, 83, 69, 127, 8, 26, 128, 7, 125, | ||||
| 	4, 129, 134, 28, 116, 136, 137, 53, 24, 66, | ||||
| 	22, 35, 34, 33, 21, 19, 56, 17, 9, 6, | ||||
| 	5, 3, 1, | ||||
| } | ||||
| var yyPact = [...]int{ | ||||
|  | ||||
| 	45, -1000, -1000, 44, -1000, -1000, -1000, -1000, -1000, -1000, | ||||
| 	73, 71, -1000, 70, 69, 68, 45, 34, -1000, 8, | ||||
| 	-1000, 26, 33, -1000, -1000, -1000, 30, -1000, -1000, 66, | ||||
| 	55, -1000, -1000, -1000, -1000, -1000, -4, -1000, 64, -1000, | ||||
| 	49, -1000, -1000, 51, -1000, -1000, -1000, -1000, -1000, -1000, | ||||
| 	83, 82, -1000, 81, 78, 76, 49, 36, -1000, 9, | ||||
| 	-1000, 27, 33, -1000, -1000, -1000, 31, -1000, -1000, 50, | ||||
| 	63, -1000, -1000, -1000, -1000, -1000, -4, -1000, 73, -1000, | ||||
| 	-1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, | ||||
| 	-1000, -1000, -1000, 89, -2, 25, -3, 0, -1000, -1000, | ||||
| 	-1000, -11, 57, -1000, -1000, 26, -20, 22, 42, 67, | ||||
| 	-1000, 66, 53, 53, -7, -1000, 20, 40, 26, -1, | ||||
| 	-2, 28, -1000, -1000, -1000, -1000, -1000, -13, -16, -1000, | ||||
| 	-1000, 26, -26, 57, 53, -1000, 26, -1000, -1000, -1000, | ||||
| 	27, -1000, -1000, 14, 39, 50, 105, -5, 26, -23, | ||||
| 	-1000, 11, 38, 53, -1000, 53, -1000, 26, -1000, 105, | ||||
| 	-1000, -29, 37, -27, -1000, -31, 26, -1000, -6, 26, | ||||
| 	-1000, 53, -1000, 36, -1000, | ||||
| 	-1000, -1000, -1000, 93, 52, 23, -3, 8, 74, -1000, | ||||
| 	-1000, -1000, -12, 58, -1000, -1000, 27, -21, 22, 45, | ||||
| 	66, -1000, 50, 61, 0, 61, -7, -1000, 21, 43, | ||||
| 	27, -1, 52, 30, -1000, -1000, -1000, -1000, -1000, 61, | ||||
| 	-10, -16, -1000, -1000, 27, -26, 58, 61, -1000, 27, | ||||
| 	-1000, -1000, -1000, -1000, 26, -1000, -1000, 20, 42, 3, | ||||
| 	114, -5, 27, -24, -1000, 14, 39, 61, -1000, 61, | ||||
| 	-1000, 27, -1000, 114, -1000, -29, 38, -27, -1000, -30, | ||||
| 	27, -1000, -6, 27, -1000, 61, -1000, 28, -1000, | ||||
| } | ||||
| var yyPgo = [...]int{ | ||||
|  | ||||
| 	0, 147, 98, 0, 146, 107, 145, 144, 104, 101, | ||||
| 	143, 142, 10, 141, 140, 139, 138, 1, 8, 137, | ||||
| 	136, 135, 2, 6, 14, 134, 133, 5, 130, 129, | ||||
| 	3, 127, 126, 125, 122, 7, 119, 117, 4, 109, | ||||
| 	106, | ||||
| 	0, 152, 116, 0, 151, 113, 150, 149, 111, 108, | ||||
| 	148, 147, 9, 146, 10, 145, 144, 1, 7, 143, | ||||
| 	142, 141, 2, 6, 20, 140, 139, 5, 138, 137, | ||||
| 	3, 134, 131, 129, 126, 8, 123, 122, 4, 110, | ||||
| 	96, | ||||
| } | ||||
| var yyR1 = [...]int{ | ||||
|  | ||||
| 	0, 1, 3, 3, 2, 2, 4, 4, 4, 4, | ||||
| 	4, 4, 5, 12, 12, 13, 13, 11, 14, 6, | ||||
| 	6, 15, 16, 7, 17, 17, 17, 17, 18, 22, | ||||
| 	4, 4, 5, 12, 12, 13, 13, 13, 11, 14, | ||||
| 	6, 6, 15, 16, 7, 17, 17, 17, 17, 18, | ||||
| 	22, 22, 22, 22, 22, 22, 22, 22, 22, 22, | ||||
| 	24, 24, 24, 24, 23, 19, 20, 20, 21, 26, | ||||
| 	8, 25, 27, 27, 29, 9, 28, 30, 30, 32, | ||||
| 	31, 33, 31, 10, 34, 35, 35, 36, 37, 38, | ||||
| 	38, 39, 40, | ||||
| 	22, 24, 24, 24, 24, 23, 19, 20, 20, 21, | ||||
| 	26, 8, 25, 27, 27, 29, 9, 28, 30, 30, | ||||
| 	32, 31, 33, 31, 10, 34, 35, 35, 36, 37, | ||||
| 	38, 38, 39, 40, | ||||
| } | ||||
| var yyR2 = [...]int{ | ||||
|  | ||||
| 	0, 1, 1, 1, 2, 3, 1, 1, 1, 1, | ||||
| 	1, 1, 5, 1, 3, 1, 3, 1, 1, 4, | ||||
| 	4, 1, 0, 3, 1, 1, 1, 1, 2, 1, | ||||
| 	2, 1, 1, 1, 1, 1, 1, 1, 1, 1, | ||||
| 	1, 1, 1, 1, 1, 5, 5, 4, 3, 0, | ||||
| 	6, 1, 2, 3, 0, 10, 1, 2, 3, 0, | ||||
| 	5, 0, 4, 7, 1, 2, 3, 8, 1, 2, | ||||
| 	3, 8, 1, | ||||
| 	1, 1, 5, 1, 3, 1, 4, 3, 1, 1, | ||||
| 	4, 4, 1, 0, 3, 1, 1, 1, 1, 2, | ||||
| 	1, 2, 1, 1, 1, 1, 1, 1, 1, 1, | ||||
| 	1, 1, 1, 1, 1, 1, 5, 5, 4, 3, | ||||
| 	0, 6, 1, 2, 3, 0, 10, 1, 2, 3, | ||||
| 	0, 5, 0, 4, 7, 1, 2, 3, 8, 1, | ||||
| 	2, 3, 8, 1, | ||||
| } | ||||
| var yyChk = [...]int{ | ||||
|  | ||||
| 	-1000, -1, -2, -4, -5, -6, -7, -8, -9, -10, | ||||
| 	9, 6, 15, 13, 16, 26, 28, -11, 23, -15, | ||||
| 	23, -16, -25, 23, -28, 23, -34, 23, -2, 29, | ||||
| 	32, -17, -18, -19, -20, -21, -22, -24, 17, 10, | ||||
| 	9, 6, 15, 13, 16, 26, 29, -11, 23, -15, | ||||
| 	23, -16, -25, 23, -28, 23, -34, 23, -2, 30, | ||||
| 	33, -17, -18, -19, -20, -21, -22, -24, 17, 10, | ||||
| 	8, 4, 12, 11, -5, -8, -9, 23, 19, 20, | ||||
| 	21, 22, 29, -29, 29, -12, -13, -14, 23, 23, | ||||
| 	24, -23, 37, 23, -24, -26, 14, -35, -36, 27, | ||||
| 	30, 31, 32, 33, 35, -23, -27, -17, 38, 30, | ||||
| 	28, -37, 23, -12, -3, 23, 24, -3, -3, 36, | ||||
| 	30, 28, -18, -22, 32, -35, 29, 34, 36, -27, | ||||
| 	39, -23, -3, -38, -39, -22, 29, 30, 28, -40, | ||||
| 	23, -30, -31, 5, 7, 32, -38, 38, 30, 28, | ||||
| 	-3, -33, -3, -22, -30, -32, 40, 28, 39, 40, | ||||
| 	-17, 32, -17, -3, 28, | ||||
| 	21, 22, 30, -29, 30, -12, -13, -14, 28, 23, | ||||
| 	23, 24, -23, 38, 23, -24, -26, 14, -35, -36, | ||||
| 	27, 31, 32, 33, -14, 34, 36, -23, -27, -17, | ||||
| 	39, 31, 29, -37, 23, -12, -3, 23, 24, 33, | ||||
| 	-3, -3, 37, 31, 29, -18, -22, 33, -35, 30, | ||||
| 	-3, 35, 37, -27, 40, -23, -3, -38, -39, -22, | ||||
| 	30, 31, 29, -40, 23, -30, -31, 5, 7, 33, | ||||
| 	-38, 39, 31, 29, -3, -33, -3, -22, -30, -32, | ||||
| 	41, 29, 40, 41, -17, 33, -17, -3, 29, | ||||
| } | ||||
| var yyDef = [...]int{ | ||||
|  | ||||
| 	0, -2, 1, 0, 6, 7, 8, 9, 10, 11, | ||||
| 	0, 0, 22, 0, 0, 0, 4, 0, 17, 0, | ||||
| 	21, 0, 0, 51, 54, 56, 0, 64, 5, 0, | ||||
| 	0, 23, 24, 25, 26, 27, 0, 29, 0, 31, | ||||
| 	32, 33, 34, 35, 36, 37, 38, 39, 40, 41, | ||||
| 	42, 43, 49, 0, 0, 0, 13, 15, 18, 19, | ||||
| 	20, 28, 0, 44, 30, 0, 0, 0, 0, 0, | ||||
| 	12, 0, 0, 0, 0, 48, 0, 0, 0, 0, | ||||
| 	65, 0, 68, 14, 16, 2, 3, 0, 0, 47, | ||||
| 	50, 52, 0, 0, 0, 66, 0, 45, 46, 53, | ||||
| 	0, 28, 63, 0, 0, 0, 0, 0, 69, 0, | ||||
| 	72, 0, 0, 0, 61, 0, 70, 0, 55, 57, | ||||
| 	59, 0, 0, 0, 58, 0, 0, 67, 0, 0, | ||||
| 	62, 0, 60, 0, 71, | ||||
| 	0, 0, 23, 0, 0, 0, 4, 0, 18, 0, | ||||
| 	22, 0, 0, 52, 55, 57, 0, 65, 5, 0, | ||||
| 	0, 24, 25, 26, 27, 28, 0, 30, 0, 32, | ||||
| 	33, 34, 35, 36, 37, 38, 39, 40, 41, 42, | ||||
| 	43, 44, 50, 0, 0, 0, 13, 15, 0, 19, | ||||
| 	20, 21, 29, 0, 45, 31, 0, 0, 0, 0, | ||||
| 	0, 12, 0, 0, 0, 0, 0, 49, 0, 0, | ||||
| 	0, 0, 66, 0, 69, 14, 17, 2, 3, 0, | ||||
| 	0, 0, 48, 51, 53, 0, 0, 0, 67, 0, | ||||
| 	16, 46, 47, 54, 0, 29, 64, 0, 0, 0, | ||||
| 	0, 0, 70, 0, 73, 0, 0, 0, 62, 0, | ||||
| 	71, 0, 56, 58, 60, 0, 0, 0, 59, 0, | ||||
| 	0, 68, 0, 0, 63, 0, 61, 0, 72, | ||||
| } | ||||
| var yyTok1 = [...]int{ | ||||
|  | ||||
| @@ -226,21 +229,21 @@ var yyTok1 = [...]int{ | ||||
| 	3, 3, 3, 3, 3, 3, 3, 3, 3, 3, | ||||
| 	3, 3, 3, 3, 3, 3, 3, 3, 3, 3, | ||||
| 	3, 3, 3, 3, 3, 3, 3, 3, 3, 3, | ||||
| 	38, 39, 37, 3, 31, 3, 3, 3, 3, 3, | ||||
| 	3, 3, 3, 3, 3, 3, 3, 3, 40, 28, | ||||
| 	35, 32, 36, 3, 3, 3, 3, 3, 3, 3, | ||||
| 	39, 40, 38, 3, 32, 3, 3, 3, 3, 3, | ||||
| 	3, 3, 3, 3, 3, 3, 3, 3, 41, 29, | ||||
| 	36, 33, 37, 3, 3, 3, 3, 3, 3, 3, | ||||
| 	3, 3, 3, 3, 3, 3, 3, 3, 3, 3, | ||||
| 	3, 3, 3, 3, 3, 3, 3, 3, 3, 3, | ||||
| 	3, 33, 3, 34, 3, 3, 3, 3, 3, 3, | ||||
| 	3, 34, 3, 35, 3, 3, 3, 3, 3, 3, | ||||
| 	3, 3, 3, 3, 3, 3, 3, 3, 3, 3, | ||||
| 	3, 3, 3, 3, 3, 3, 3, 3, 3, 3, | ||||
| 	3, 3, 3, 29, 3, 30, | ||||
| 	3, 3, 3, 30, 3, 31, | ||||
| } | ||||
| var yyTok2 = [...]int{ | ||||
|  | ||||
| 	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, | ||||
| 	22, 23, 24, 25, 26, 27, 28, | ||||
| } | ||||
| var yyTok3 = [...]int{ | ||||
| 	0, | ||||
| @@ -585,13 +588,13 @@ yydefault: | ||||
|  | ||||
| 	case 12: | ||||
| 		yyDollar = yyS[yypt-5 : yypt+1] | ||||
| 		//line sunrpc.y:86 | ||||
| 		//line sunrpc.y:87 | ||||
| 		{ | ||||
| 			StartEnum(yyDollar[2].val) | ||||
| 		} | ||||
| 	case 15: | ||||
| 		yyDollar = yyS[yypt-1 : yypt+1] | ||||
| 		//line sunrpc.y:95 | ||||
| 		//line sunrpc.y:96 | ||||
| 		{ | ||||
| 			err := AddEnumAutoVal(yyDollar[1].val) | ||||
| 			if err != nil { | ||||
| @@ -600,8 +603,18 @@ yydefault: | ||||
| 			} | ||||
| 		} | ||||
| 	case 16: | ||||
| 		yyDollar = yyS[yypt-4 : yypt+1] | ||||
| 		//line sunrpc.y:103 | ||||
| 		{ | ||||
| 			err := AddEnumValMeta(yyDollar[2].val, yyDollar[4].val, yyDollar[1].val) | ||||
| 			if err != nil { | ||||
| 				yylex.Error(err.Error()) | ||||
| 				return 1 | ||||
| 			} | ||||
| 		} | ||||
| 	case 17: | ||||
| 		yyDollar = yyS[yypt-3 : yypt+1] | ||||
| 		//line sunrpc.y:102 | ||||
| 		//line sunrpc.y:110 | ||||
| 		{ | ||||
| 			err := AddEnumVal(yyDollar[1].val, yyDollar[3].val) | ||||
| 			if err != nil { | ||||
| @@ -609,9 +622,9 @@ yydefault: | ||||
| 				return 1 | ||||
| 			} | ||||
| 		} | ||||
| 	case 20: | ||||
| 	case 21: | ||||
| 		yyDollar = yyS[yypt-4 : yypt+1] | ||||
| 		//line sunrpc.y:124 | ||||
| 		//line sunrpc.y:132 | ||||
| 		{ | ||||
| 			err := AddConst(yyDollar[2].val, yyDollar[4].val) | ||||
| 			if err != nil { | ||||
| @@ -619,147 +632,147 @@ yydefault: | ||||
| 				return 1 | ||||
| 			} | ||||
| 		} | ||||
| 	case 22: | ||||
| 	case 23: | ||||
| 		yyDollar = yyS[yypt-1 : yypt+1] | ||||
| 		//line sunrpc.y:138 | ||||
| 		//line sunrpc.y:146 | ||||
| 		{ | ||||
| 			StartTypedef() | ||||
| 		} | ||||
| 	case 28: | ||||
| 	case 29: | ||||
| 		yyDollar = yyS[yypt-2 : yypt+1] | ||||
| 		//line sunrpc.y:149 | ||||
| 		//line sunrpc.y:157 | ||||
| 		{ | ||||
| 			AddDeclaration(yyDollar[2].val, yyDollar[1].val) | ||||
| 		} | ||||
| 	case 30: | ||||
| 	case 31: | ||||
| 		yyDollar = yyS[yypt-2 : yypt+1] | ||||
| 		//line sunrpc.y:154 | ||||
| 		//line sunrpc.y:162 | ||||
| 		{ | ||||
| 			yyVAL.val = "u" + yyDollar[2].val | ||||
| 		} | ||||
| 	case 31: | ||||
| 	case 32: | ||||
| 		yyDollar = yyS[yypt-1 : yypt+1] | ||||
| 		//line sunrpc.y:155 | ||||
| 		//line sunrpc.y:163 | ||||
| 		{ | ||||
| 			yyVAL.val = "float32" | ||||
| 		} | ||||
| 	case 32: | ||||
| 	case 33: | ||||
| 		yyDollar = yyS[yypt-1 : yypt+1] | ||||
| 		//line sunrpc.y:156 | ||||
| 		//line sunrpc.y:164 | ||||
| 		{ | ||||
| 			yyVAL.val = "float64" | ||||
| 		} | ||||
| 	case 33: | ||||
| 	case 34: | ||||
| 		yyDollar = yyS[yypt-1 : yypt+1] | ||||
| 		//line sunrpc.y:157 | ||||
| 		//line sunrpc.y:165 | ||||
| 		{ | ||||
| 			yyVAL.val = "bool" | ||||
| 		} | ||||
| 	case 34: | ||||
| 	case 35: | ||||
| 		yyDollar = yyS[yypt-1 : yypt+1] | ||||
| 		//line sunrpc.y:158 | ||||
| 		//line sunrpc.y:166 | ||||
| 		{ | ||||
| 			yyVAL.val = "string" | ||||
| 		} | ||||
| 	case 35: | ||||
| 		yyDollar = yyS[yypt-1 : yypt+1] | ||||
| 		//line sunrpc.y:159 | ||||
| 		{ | ||||
| 			yyVAL.val = "byte" | ||||
| 		} | ||||
| 	case 40: | ||||
| 	case 36: | ||||
| 		yyDollar = yyS[yypt-1 : yypt+1] | ||||
| 		//line sunrpc.y:167 | ||||
| 		{ | ||||
| 			yyVAL.val = "int64" | ||||
| 			yyVAL.val = "byte" | ||||
| 		} | ||||
| 	case 41: | ||||
| 		yyDollar = yyS[yypt-1 : yypt+1] | ||||
| 		//line sunrpc.y:168 | ||||
| 		//line sunrpc.y:175 | ||||
| 		{ | ||||
| 			yyVAL.val = "int32" | ||||
| 			yyVAL.val = "int64" | ||||
| 		} | ||||
| 	case 42: | ||||
| 		yyDollar = yyS[yypt-1 : yypt+1] | ||||
| 		//line sunrpc.y:169 | ||||
| 		//line sunrpc.y:176 | ||||
| 		{ | ||||
| 			yyVAL.val = "int16" | ||||
| 			yyVAL.val = "int32" | ||||
| 		} | ||||
| 	case 43: | ||||
| 		yyDollar = yyS[yypt-1 : yypt+1] | ||||
| 		//line sunrpc.y:170 | ||||
| 		//line sunrpc.y:177 | ||||
| 		{ | ||||
| 			yyVAL.val = "int16" | ||||
| 		} | ||||
| 	case 44: | ||||
| 		yyDollar = yyS[yypt-1 : yypt+1] | ||||
| 		//line sunrpc.y:178 | ||||
| 		{ | ||||
| 			yyVAL.val = "int8" | ||||
| 		} | ||||
| 	case 45: | ||||
| 	case 46: | ||||
| 		yyDollar = yyS[yypt-5 : yypt+1] | ||||
| 		//line sunrpc.y:178 | ||||
| 		//line sunrpc.y:186 | ||||
| 		{ | ||||
| 			AddFixedArray(yyDollar[2].val, yyDollar[1].val, yyDollar[4].val) | ||||
| 		} | ||||
| 	case 46: | ||||
| 	case 47: | ||||
| 		yyDollar = yyS[yypt-5 : yypt+1] | ||||
| 		//line sunrpc.y:182 | ||||
| 		//line sunrpc.y:190 | ||||
| 		{ | ||||
| 			AddVariableArray(yyDollar[2].val, yyDollar[1].val, yyDollar[4].val) | ||||
| 		} | ||||
| 	case 47: | ||||
| 	case 48: | ||||
| 		yyDollar = yyS[yypt-4 : yypt+1] | ||||
| 		//line sunrpc.y:183 | ||||
| 		//line sunrpc.y:191 | ||||
| 		{ | ||||
| 			AddVariableArray(yyDollar[2].val, yyDollar[1].val, "") | ||||
| 		} | ||||
| 	case 48: | ||||
| 	case 49: | ||||
| 		yyDollar = yyS[yypt-3 : yypt+1] | ||||
| 		//line sunrpc.y:191 | ||||
| 		//line sunrpc.y:199 | ||||
| 		{ | ||||
| 			AddOptValue(yyDollar[3].val, yyDollar[1].val) | ||||
| 		} | ||||
| 	case 49: | ||||
| 	case 50: | ||||
| 		yyDollar = yyS[yypt-3 : yypt+1] | ||||
| 		//line sunrpc.y:195 | ||||
| 		//line sunrpc.y:203 | ||||
| 		{ | ||||
| 			StartStruct(yyDollar[2].val) | ||||
| 		} | ||||
| 	case 50: | ||||
| 	case 51: | ||||
| 		yyDollar = yyS[yypt-6 : yypt+1] | ||||
| 		//line sunrpc.y:195 | ||||
| 		//line sunrpc.y:203 | ||||
| 		{ | ||||
| 			AddStruct() | ||||
| 		} | ||||
| 	case 54: | ||||
| 	case 55: | ||||
| 		yyDollar = yyS[yypt-2 : yypt+1] | ||||
| 		//line sunrpc.y:208 | ||||
| 		//line sunrpc.y:216 | ||||
| 		{ | ||||
| 			StartUnion(yyDollar[2].val) | ||||
| 		} | ||||
| 	case 55: | ||||
| 	case 56: | ||||
| 		yyDollar = yyS[yypt-10 : yypt+1] | ||||
| 		//line sunrpc.y:208 | ||||
| 		//line sunrpc.y:216 | ||||
| 		{ | ||||
| 			AddUnion() | ||||
| 		} | ||||
| 	case 59: | ||||
| 	case 60: | ||||
| 		yyDollar = yyS[yypt-2 : yypt+1] | ||||
| 		//line sunrpc.y:221 | ||||
| 		//line sunrpc.y:229 | ||||
| 		{ | ||||
| 			StartCase(yyDollar[2].val) | ||||
| 		} | ||||
| 	case 60: | ||||
| 	case 61: | ||||
| 		yyDollar = yyS[yypt-5 : yypt+1] | ||||
| 		//line sunrpc.y:221 | ||||
| 		//line sunrpc.y:229 | ||||
| 		{ | ||||
| 			AddCase() | ||||
| 		} | ||||
| 	case 61: | ||||
| 	case 62: | ||||
| 		yyDollar = yyS[yypt-1 : yypt+1] | ||||
| 		//line sunrpc.y:222 | ||||
| 		//line sunrpc.y:230 | ||||
| 		{ | ||||
| 			StartCase("default") | ||||
| 		} | ||||
| 	case 62: | ||||
| 	case 63: | ||||
| 		yyDollar = yyS[yypt-4 : yypt+1] | ||||
| 		//line sunrpc.y:222 | ||||
| 		//line sunrpc.y:230 | ||||
| 		{ | ||||
| 			AddCase() | ||||
| 		} | ||||
|   | ||||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										795
									
								
								libvirt.gen.go
									
									
									
									
									
								
							
							
						
						
									
										795
									
								
								libvirt.gen.go
									
									
									
									
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							| @@ -17,6 +17,7 @@ | ||||
| package libvirt | ||||
|  | ||||
| import ( | ||||
| 	"bytes" | ||||
| 	"encoding/xml" | ||||
| 	"net" | ||||
| 	"sync" | ||||
| @@ -252,6 +253,58 @@ func TestXMLIntegration(t *testing.T) { | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func TestVolumeUploadDownloadIntegration(t *testing.T) { | ||||
| 	testdata := []byte("Hello, world!") | ||||
| 	l := New(testConn(t)) | ||||
|  | ||||
| 	if err := l.Connect(); err != nil { | ||||
| 		t.Error(err) | ||||
| 	} | ||||
| 	defer l.Disconnect() | ||||
|  | ||||
| 	pool, err := l.StoragePool("test") | ||||
| 	if err != nil { | ||||
| 		t.Fatal(err) | ||||
| 	} | ||||
|  | ||||
| 	var volObj struct { | ||||
| 		XMLName  xml.Name `xml:"volume"` | ||||
| 		Name     string   `xml:"name"` | ||||
| 		Capacity struct { | ||||
| 			Value uint64 `xml:",chardata"` | ||||
| 		} `xml:"capacity"` | ||||
| 		Target struct { | ||||
| 			Format struct { | ||||
| 				Type string `xml:"type,attr"` | ||||
| 			} `xml:"format"` | ||||
| 		} `xml:"target"` | ||||
| 	} | ||||
| 	volObj.Name = "testvol" | ||||
| 	volObj.Capacity.Value = uint64(len(testdata)) | ||||
| 	volObj.Target.Format.Type = "raw" | ||||
| 	xmlVol, err := xml.Marshal(volObj) | ||||
| 	if err != nil { | ||||
| 		t.Fatal(err) | ||||
| 	} | ||||
| 	vol, err := l.StorageVolCreateXML(pool, string(xmlVol), 0) | ||||
| 	if err != nil { | ||||
| 		t.Fatal(err) | ||||
| 	} | ||||
| 	defer l.StorageVolDelete(vol, 0) | ||||
| 	err = l.StorageVolUpload(vol, bytes.NewBuffer(testdata), 0, 0, 0) | ||||
| 	if err != nil { | ||||
| 		t.Fatal(err) | ||||
| 	} | ||||
| 	var buf bytes.Buffer | ||||
| 	err = l.StorageVolDownload(vol, &buf, 0, 0, 0) | ||||
| 	if err != nil { | ||||
| 		t.Fatal(err) | ||||
| 	} | ||||
| 	if bytes.Compare(testdata, buf.Bytes()) != 0 { | ||||
| 		t.Fatal("download not what we uploaded") | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // verify we're able to concurrently communicate with libvirtd. | ||||
| // see: https://github.com/digitalocean/go-libvirt/pull/52 | ||||
| func Test_concurrentWrite(t *testing.T) { | ||||
|   | ||||
							
								
								
									
										118
									
								
								rpc.go
									
									
									
									
									
								
							
							
						
						
									
										118
									
								
								rpc.go
									
									
									
									
									
								
							| @@ -174,10 +174,12 @@ func (l *Libvirt) callback(id uint32, res response) { | ||||
| 	c, ok := l.callbacks[id] | ||||
| 	l.cm.Unlock() | ||||
| 	if ok { | ||||
| 		// we close channel in deregister() so that we don't block here forever without receiver | ||||
| 		defer func() { | ||||
| 			recover() | ||||
| 		}() | ||||
| 		c <- res | ||||
| 	} | ||||
|  | ||||
| 	l.deregister(id) | ||||
| } | ||||
|  | ||||
| // route sends incoming packets to their listeners. | ||||
| @@ -274,11 +276,107 @@ func (l *Libvirt) deregister(id uint32) { | ||||
| // returns response returned by server. | ||||
| // if response is not OK, decodes error from it and returns it. | ||||
| func (l *Libvirt) request(proc uint32, program uint32, payload []byte) (response, error) { | ||||
| 	return l.requestStream(proc, program, payload, nil, nil) | ||||
| } | ||||
|  | ||||
| func (l *Libvirt) processIncomingStream(c chan response, inStream io.Writer) (response, error) { | ||||
| 	for { | ||||
| 		resp, err := l.getResponse(c) | ||||
| 		if err != nil { | ||||
| 			return resp, err | ||||
| 		} | ||||
| 		// StatusOK here means end of stream | ||||
| 		if resp.Status == StatusOK { | ||||
| 			return resp, nil | ||||
| 		} | ||||
| 		// StatusError is handled in getResponse, so this is StatusContinue | ||||
| 		// StatusContinue is valid here only for stream packets | ||||
| 		// libvirtd breaks protocol and returns StatusContinue with empty Payload when stream finishes | ||||
| 		if len(resp.Payload) == 0 { | ||||
| 			return resp, nil | ||||
| 		} | ||||
| 		if inStream != nil { | ||||
| 			_, err = inStream.Write(resp.Payload) | ||||
| 			if err != nil { | ||||
| 				return response{}, err | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func (l *Libvirt) requestStream(proc uint32, program uint32, payload []byte, outStream io.Reader, inStream io.Writer) (response, error) { | ||||
| 	serial := l.serial() | ||||
| 	c := make(chan response) | ||||
|  | ||||
| 	l.register(serial, c) | ||||
| 	defer l.deregister(serial) | ||||
|  | ||||
| 	err := l.sendPacket(serial, proc, program, payload, Call, StatusOK) | ||||
| 	if err != nil { | ||||
| 		return response{}, err | ||||
| 	} | ||||
|  | ||||
| 	resp, err := l.getResponse(c) | ||||
| 	if err != nil { | ||||
| 		return resp, err | ||||
| 	} | ||||
|  | ||||
| 	if outStream != nil { | ||||
| 		abortOutStream := make(chan bool) | ||||
| 		outStreamErr := make(chan error) | ||||
| 		go func() { | ||||
| 			outStreamErr <- l.sendStream(serial, proc, program, outStream, abortOutStream) | ||||
| 		}() | ||||
|  | ||||
| 		// Even without incoming stream server sends confirmation once all data is received | ||||
| 		resp, err = l.processIncomingStream(c, inStream) | ||||
| 		if err != nil { | ||||
| 			abortOutStream <- true | ||||
| 			return resp, err | ||||
| 		} | ||||
|  | ||||
| 		err = <-outStreamErr | ||||
| 		if err != nil { | ||||
| 			return response{}, err | ||||
| 		} | ||||
| 	} else if inStream != nil { | ||||
| 		return l.processIncomingStream(c, inStream) | ||||
| 	} | ||||
|  | ||||
| 	return resp, nil | ||||
| } | ||||
|  | ||||
| func (l *Libvirt) sendStream(serial uint32, proc uint32, program uint32, stream io.Reader, abort chan bool) error { | ||||
| 	// Keep total packet length under 4 MiB to follow possible limitation in libvirt server code | ||||
| 	buf := make([]byte, 4*MiB-constants.HeaderSize) | ||||
| 	for { | ||||
| 		select { | ||||
| 		case <-abort: | ||||
| 			return l.sendPacket(serial, proc, program, nil, Stream, StatusError) | ||||
| 		default: | ||||
| 		} | ||||
| 		n, err := stream.Read(buf) | ||||
| 		if err != nil { | ||||
| 			if err == io.EOF { | ||||
| 				return l.sendPacket(serial, proc, program, nil, Stream, StatusOK) | ||||
| 			} | ||||
| 			// keep original error | ||||
| 			err2 := l.sendPacket(serial, proc, program, nil, Stream, StatusError) | ||||
| 			if err2 != nil { | ||||
| 				return err2 | ||||
| 			} | ||||
| 			return err | ||||
| 		} | ||||
| 		if n > 0 { | ||||
| 			err = l.sendPacket(serial, proc, program, buf[:n], Stream, StatusContinue) | ||||
| 			if err != nil { | ||||
| 				return err | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func (l *Libvirt) sendPacket(serial uint32, proc uint32, program uint32, payload []byte, typ uint32, status uint32) error { | ||||
| 	size := constants.PacketLengthSize + constants.HeaderSize | ||||
| 	if payload != nil { | ||||
| 		size += len(payload) | ||||
| @@ -290,9 +388,9 @@ func (l *Libvirt) request(proc uint32, program uint32, payload []byte) (response | ||||
| 			Program:   program, | ||||
| 			Version:   constants.ProtocolVersion, | ||||
| 			Procedure: proc, | ||||
| 			Type:      Call, | ||||
| 			Type:      typ, | ||||
| 			Serial:    serial, | ||||
| 			Status:    StatusOK, | ||||
| 			Status:    status, | ||||
| 		}, | ||||
| 	} | ||||
|  | ||||
| @@ -301,23 +399,23 @@ func (l *Libvirt) request(proc uint32, program uint32, payload []byte) (response | ||||
| 	defer l.mu.Unlock() | ||||
| 	err := binary.Write(l.w, binary.BigEndian, p) | ||||
| 	if err != nil { | ||||
| 		return response{}, err | ||||
| 		return err | ||||
| 	} | ||||
|  | ||||
| 	// write payload | ||||
| 	if payload != nil { | ||||
| 		err = binary.Write(l.w, binary.BigEndian, payload) | ||||
| 		if err != nil { | ||||
| 			return response{}, err | ||||
| 			return err | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	if err := l.w.Flush(); err != nil { | ||||
| 		return response{}, err | ||||
| 	} | ||||
| 	return l.w.Flush() | ||||
| } | ||||
|  | ||||
| func (l *Libvirt) getResponse(c chan response) (response, error) { | ||||
| 	resp := <-c | ||||
| 	if resp.Status != StatusOK { | ||||
| 	if resp.Status == StatusError { | ||||
| 		return resp, decodeError(resp.Payload) | ||||
| 	} | ||||
|  | ||||
|   | ||||
							
								
								
									
										27
									
								
								units.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										27
									
								
								units.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,27 @@ | ||||
| // Copyright 2016 The go-libvirt Authors. | ||||
| // | ||||
| // Licensed under the Apache License, Version 2.0 (the "License"); | ||||
| // you may not use this file except in compliance with the License. | ||||
| // You may obtain a copy of the License at | ||||
| // | ||||
| //   http://www.apache.org/licenses/LICENSE-2.0 | ||||
| // | ||||
| // Unless required by applicable law or agreed to in writing, software | ||||
| // distributed under the License is distributed on an "AS IS" BASIS, | ||||
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||
| // See the License for the specific language governing permissions and | ||||
| // limitations under the License. | ||||
|  | ||||
| // This module provides different units of measurement to make other | ||||
| // code more readable. | ||||
|  | ||||
| package libvirt | ||||
|  | ||||
| const ( | ||||
|     // B - byte | ||||
| 	B   = 1 | ||||
|     // KiB - kibibyte | ||||
| 	KiB = 1024 * B | ||||
|     // MiB - mebibyte | ||||
| 	MiB = 1024 * KiB | ||||
| ) | ||||
		Reference in New Issue
	
	Block a user