@@ -21,6 +21,7 @@ import (
21
21
"context"
22
22
"fmt"
23
23
"io/ioutil"
24
+ "net"
24
25
"os"
25
26
"strings"
26
27
"time"
@@ -64,7 +65,7 @@ func readRainsConfig() (UDPAddr, error) {
64
65
return address , nil
65
66
}
66
67
67
- func rainsQuery (ctx context.Context , server UDPAddr , hostname string ) (addr scionAddr , err error ) {
68
+ func rainsQuery (ctx context.Context , server UDPAddr , hostname string ) (scionAddr , error ) {
68
69
const (
69
70
rainsCtx = "." // use global context
70
71
qType = rains .OTScionAddr // request SCION addresses
@@ -73,40 +74,48 @@ func rainsQuery(ctx context.Context, server UDPAddr, hostname string) (addr scio
73
74
)
74
75
qOpts := []rains.Option {} // no options
75
76
76
- // TODO(matzf): check that this actually works
77
- // - return error on timeout, network problems, invalid format, ...
78
- // - return HostNotFoundError error if all went well, but host not found
79
77
// TODO(chaehni): This call can sometimes cause a timeout even though the server is reachable (see issue #221)
80
- // The timeout value has been decreased to counter this behavior until the problem is resolved.
78
+ // The (default) timeout value has been decreased to counter this behavior until the problem is resolved.
81
79
srv := server .snetUDPAddr ()
82
80
81
+ reply , err := rainsQueryChecked (ctx , hostname , rainsCtx , []rains.Type {qType }, qOpts , expire , timeout , srv )
82
+ if err != nil {
83
+ return scionAddr {}, err
84
+ }
85
+ addrStr , ok := reply [qType ]
86
+ if ! ok {
87
+ return scionAddr {}, & HostNotFoundError {hostname }
88
+ }
89
+ addr , err := parseSCIONAddr (addrStr )
90
+ if err != nil {
91
+ return scionAddr {}, fmt .Errorf ("address for host %q invalid: %w" , hostname , err )
92
+ }
93
+ return addr , nil
94
+ }
95
+
96
+ func rainsQueryChecked (ctx context.Context , name , rainsCtx string , types []rains.Type , opts []rains.Option ,
97
+ expire , timeout time.Duration , addr net.Addr ) (res map [rains.Type ]string , err error ) {
98
+
99
+ var contextTimeout time.Duration
100
+ deadline , finite := ctx .Deadline ()
101
+ if finite {
102
+ contextTimeout = time .Until (deadline )
103
+ if contextTimeout < 0 {
104
+ return res , context .DeadlineExceeded
105
+ }
106
+ } else {
107
+ contextTimeout = timeout
108
+ }
109
+
83
110
done := make (chan struct {})
84
111
go func () {
85
112
defer close (done )
86
- var reply map [rains.Type ]string
87
- reply , err = rains .Query (hostname , rainsCtx , []rains.Type {qType }, qOpts , expire , timeout , srv )
88
- if err != nil {
89
- err = fmt .Errorf ("address for host %q not found: %w" , hostname , err )
90
- return
91
- }
92
- addrStr , ok := reply [qType ]
93
- if ! ok {
94
- err = & HostNotFoundError {hostname }
95
- return
96
- }
97
- addr , err = parseSCIONAddr (addrStr )
98
- if err != nil {
99
- err = fmt .Errorf ("address for host %q invalid: %w" , hostname , err )
100
- addr = scionAddr {}
101
- }
113
+ res , err = rains .Query (name , rainsCtx , types , opts , expire , contextTimeout , addr )
102
114
}()
103
115
select {
104
116
case <- ctx .Done ():
105
- return scionAddr {}, context . DeadlineExceeded
117
+ return res , ctx . Err ()
106
118
case <- done :
107
119
}
108
- if err != nil {
109
- return scionAddr {}, err
110
- }
111
- return addr , nil
120
+ return
112
121
}
0 commit comments