github.com/SagerNet/gvisor@v0.0.0-20210707092255-7731c139d75c/pkg/unet/unet_test.go (about) 1 // Copyright 2018 The gVisor Authors. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package unet 16 17 import ( 18 "io/ioutil" 19 "os" 20 "path/filepath" 21 "reflect" 22 "testing" 23 "time" 24 25 "golang.org/x/sys/unix" 26 "github.com/SagerNet/gvisor/pkg/sync" 27 ) 28 29 func randomFilename() (string, error) { 30 // Return a randomly generated file in the test dir. 31 f, err := ioutil.TempFile("", "unet-test") 32 if err != nil { 33 return "", err 34 } 35 file := f.Name() 36 os.Remove(file) 37 f.Close() 38 39 cwd, err := os.Getwd() 40 if err != nil { 41 return "", err 42 } 43 44 // NOTE(b/26918832): We try to use relative path if possible. This is 45 // to help conforming to the unix path length limit. 46 if rel, err := filepath.Rel(cwd, file); err == nil { 47 return rel, nil 48 } 49 50 return file, nil 51 } 52 53 func TestConnectFailure(t *testing.T) { 54 name, err := randomFilename() 55 if err != nil { 56 t.Fatalf("Unable to generate file, got err %v expected nil", err) 57 } 58 59 if _, err := Connect(name, false); err == nil { 60 t.Fatalf("Connect was successful, expected err") 61 } 62 } 63 64 func TestBindFailure(t *testing.T) { 65 name, err := randomFilename() 66 if err != nil { 67 t.Fatalf("Unable to generate file, got err %v expected nil", err) 68 } 69 70 ss, err := BindAndListen(name, false) 71 if err != nil { 72 t.Fatalf("First bind failed, got err %v expected nil", err) 73 } 74 defer ss.Close() 75 76 if _, err = BindAndListen(name, false); err == nil { 77 t.Fatalf("Second bind succeeded, expected non-nil err") 78 } 79 } 80 81 func TestMultipleAccept(t *testing.T) { 82 name, err := randomFilename() 83 if err != nil { 84 t.Fatalf("Unable to generate file, got err %v expected nil", err) 85 } 86 87 ss, err := BindAndListen(name, false) 88 if err != nil { 89 t.Fatalf("First bind failed, got err %v expected nil", err) 90 } 91 defer ss.Close() 92 93 // Connect backlog times asynchronously. 94 var wg sync.WaitGroup 95 defer wg.Wait() 96 for i := 0; i < backlog; i++ { 97 wg.Add(1) 98 go func() { 99 defer wg.Done() 100 s, err := Connect(name, false) 101 if err != nil { 102 t.Errorf("Connect failed, got err %v expected nil", err) 103 return 104 } 105 s.Close() 106 }() 107 } 108 109 // Accept backlog times. 110 for i := 0; i < backlog; i++ { 111 s, err := ss.Accept() 112 if err != nil { 113 t.Errorf("Accept failed, got err %v expected nil", err) 114 continue 115 } 116 s.Close() 117 } 118 } 119 120 func TestServerClose(t *testing.T) { 121 name, err := randomFilename() 122 if err != nil { 123 t.Fatalf("Unable to generate file, got err %v expected nil", err) 124 } 125 126 ss, err := BindAndListen(name, false) 127 if err != nil { 128 t.Fatalf("First bind failed, got err %v expected nil", err) 129 } 130 131 // Make sure the first close succeeds. 132 if err := ss.Close(); err != nil { 133 t.Fatalf("First close failed, got err %v expected nil", err) 134 } 135 136 // The second one should fail. 137 if err := ss.Close(); err == nil { 138 t.Fatalf("Second close succeeded, expected non-nil err") 139 } 140 } 141 142 func socketPair(t *testing.T, packet bool) (*Socket, *Socket) { 143 name, err := randomFilename() 144 if err != nil { 145 t.Fatalf("Unable to generate file, got err %v expected nil", err) 146 } 147 148 // Bind a server. 149 ss, err := BindAndListen(name, packet) 150 if err != nil { 151 t.Fatalf("Error binding, got %v expected nil", err) 152 } 153 defer ss.Close() 154 155 // Accept a client. 156 acceptSocket := make(chan *Socket) 157 acceptErr := make(chan error) 158 go func() { 159 server, err := ss.Accept() 160 if err != nil { 161 acceptErr <- err 162 } 163 acceptSocket <- server 164 }() 165 166 // Connect the client. 167 client, err := Connect(name, packet) 168 if err != nil { 169 t.Fatalf("Error connecting, got %v expected nil", err) 170 } 171 172 // Grab the server handle. 173 select { 174 case server := <-acceptSocket: 175 return server, client 176 case err := <-acceptErr: 177 t.Fatalf("Accept error: %v", err) 178 } 179 panic("unreachable") 180 } 181 182 func TestSendRecv(t *testing.T) { 183 server, client := socketPair(t, false) 184 defer server.Close() 185 defer client.Close() 186 187 // Write on the client. 188 w := client.Writer(true) 189 if n, err := w.WriteVec([][]byte{{'a'}}); n != 1 || err != nil { 190 t.Fatalf("For client write, got n=%d err=%v, expected n=1 err=nil", n, err) 191 } 192 193 // Read on the server. 194 b := [][]byte{{'b'}} 195 r := server.Reader(true) 196 if n, err := r.ReadVec(b); n != 1 || err != nil { 197 t.Fatalf("For server read, got n=%d err=%v, expected n=1 err=nil", n, err) 198 } 199 if b[0][0] != 'a' { 200 t.Fatalf("Got bad read data, got %c, expected a", b[0][0]) 201 } 202 } 203 204 // TestSymmetric exists to assert that the two sockets received from socketPair 205 // are interchangeable. They should be, this just provides a basic sanity check 206 // by running TestSendRecv "backwards". 207 func TestSymmetric(t *testing.T) { 208 server, client := socketPair(t, false) 209 defer server.Close() 210 defer client.Close() 211 212 // Write on the server. 213 w := server.Writer(true) 214 if n, err := w.WriteVec([][]byte{{'a'}}); n != 1 || err != nil { 215 t.Fatalf("For server write, got n=%d err=%v, expected n=1 err=nil", n, err) 216 } 217 218 // Read on the client. 219 b := [][]byte{{'b'}} 220 r := client.Reader(true) 221 if n, err := r.ReadVec(b); n != 1 || err != nil { 222 t.Fatalf("For client read, got n=%d err=%v, expected n=1 err=nil", n, err) 223 } 224 if b[0][0] != 'a' { 225 t.Fatalf("Got bad read data, got %c, expected a", b[0][0]) 226 } 227 } 228 229 func TestPacket(t *testing.T) { 230 server, client := socketPair(t, true) 231 defer server.Close() 232 defer client.Close() 233 234 // Write on the client. 235 w := client.Writer(true) 236 if n, err := w.WriteVec([][]byte{{'a'}}); n != 1 || err != nil { 237 t.Fatalf("For client write, got n=%d err=%v, expected n=1 err=nil", n, err) 238 } 239 240 // Write on the client again. 241 w = client.Writer(true) 242 if n, err := w.WriteVec([][]byte{{'a'}}); n != 1 || err != nil { 243 t.Fatalf("For client write, got n=%d err=%v, expected n=1 err=nil", n, err) 244 } 245 246 // Read on the server. 247 // 248 // This should only get back a single byte, despite the buffer 249 // being size two. This is because it's a _packet_ buffer. 250 b := [][]byte{{'b', 'b'}} 251 r := server.Reader(true) 252 if n, err := r.ReadVec(b); n != 1 || err != nil { 253 t.Fatalf("For server read, got n=%d err=%v, expected n=1 err=nil", n, err) 254 } 255 if b[0][0] != 'a' { 256 t.Fatalf("Got bad read data, got %c, expected a", b[0][0]) 257 } 258 259 // Do it again. 260 r = server.Reader(true) 261 if n, err := r.ReadVec(b); n != 1 || err != nil { 262 t.Fatalf("For server read, got n=%d err=%v, expected n=1 err=nil", n, err) 263 } 264 if b[0][0] != 'a' { 265 t.Fatalf("Got bad read data, got %c, expected a", b[0][0]) 266 } 267 } 268 269 func TestClose(t *testing.T) { 270 server, client := socketPair(t, false) 271 defer server.Close() 272 273 // Make sure the first close succeeds. 274 if err := client.Close(); err != nil { 275 t.Fatalf("First close failed, got err %v expected nil", err) 276 } 277 278 // The second one should fail. 279 if err := client.Close(); err == nil { 280 t.Fatalf("Second close succeeded, expected non-nil err") 281 } 282 } 283 284 func TestNonBlockingSend(t *testing.T) { 285 server, client := socketPair(t, false) 286 defer server.Close() 287 defer client.Close() 288 289 // Try up to 1000 writes, of 1000 bytes. 290 blockCount := 0 291 for i := 0; i < 1000; i++ { 292 w := client.Writer(false) 293 if n, err := w.WriteVec([][]byte{make([]byte, 1000)}); n != 1000 || err != nil { 294 if err == unix.EWOULDBLOCK || err == unix.EAGAIN { 295 // We're good. That's what we wanted. 296 blockCount++ 297 } else { 298 t.Fatalf("For client write, got n=%d err=%v, expected n=1000 err=nil", n, err) 299 } 300 } 301 } 302 303 if blockCount == 1000 { 304 // Shouldn't have _always_ blocked. 305 t.Fatalf("Socket always blocked!") 306 } else if blockCount == 0 { 307 // Should have started blocking eventually. 308 t.Fatalf("Socket never blocked!") 309 } 310 } 311 312 func TestNonBlockingRecv(t *testing.T) { 313 server, client := socketPair(t, false) 314 defer server.Close() 315 defer client.Close() 316 317 b := [][]byte{{'b'}} 318 r := client.Reader(false) 319 320 // Expected to block immediately. 321 _, err := r.ReadVec(b) 322 if err != unix.EWOULDBLOCK && err != unix.EAGAIN { 323 t.Fatalf("Read didn't block, got err %v expected blocking err", err) 324 } 325 326 // Put some data in the pipe. 327 w := server.Writer(false) 328 if n, err := w.WriteVec(b); n != 1 || err != nil { 329 t.Fatalf("Write failed with n=%d err=%v, expected n=1 err=nil", n, err) 330 } 331 332 // Expect it not to block. 333 if n, err := r.ReadVec(b); n != 1 || err != nil { 334 t.Fatalf("Read failed with n=%d err=%v, expected n=1 err=nil", n, err) 335 } 336 337 // Expect it to return a block error again. 338 r = client.Reader(false) 339 _, err = r.ReadVec(b) 340 if err != unix.EWOULDBLOCK && err != unix.EAGAIN { 341 t.Fatalf("Read didn't block, got err %v expected blocking err", err) 342 } 343 } 344 345 func TestRecvVectors(t *testing.T) { 346 server, client := socketPair(t, false) 347 defer server.Close() 348 defer client.Close() 349 350 // Write on the client. 351 w := client.Writer(true) 352 if n, err := w.WriteVec([][]byte{{'a', 'b'}}); n != 2 || err != nil { 353 t.Fatalf("For client write, got n=%d err=%v, expected n=2 err=nil", n, err) 354 } 355 356 // Read on the server. 357 b := [][]byte{{'c'}, {'c'}} 358 r := server.Reader(true) 359 if n, err := r.ReadVec(b); n != 2 || err != nil { 360 t.Fatalf("For server read, got n=%d err=%v, expected n=2 err=nil", n, err) 361 } 362 if b[0][0] != 'a' || b[1][0] != 'b' { 363 t.Fatalf("Got bad read data, got %c,%c, expected a,b", b[0][0], b[1][0]) 364 } 365 } 366 367 func TestSendVectors(t *testing.T) { 368 server, client := socketPair(t, false) 369 defer server.Close() 370 defer client.Close() 371 372 // Write on the client. 373 w := client.Writer(true) 374 if n, err := w.WriteVec([][]byte{{'a'}, {'b'}}); n != 2 || err != nil { 375 t.Fatalf("For client write, got n=%d err=%v, expected n=2 err=nil", n, err) 376 } 377 378 // Read on the server. 379 b := [][]byte{{'c', 'c'}} 380 r := server.Reader(true) 381 if n, err := r.ReadVec(b); n != 2 || err != nil { 382 t.Fatalf("For server read, got n=%d err=%v, expected n=2 err=nil", n, err) 383 } 384 if b[0][0] != 'a' || b[0][1] != 'b' { 385 t.Fatalf("Got bad read data, got %c,%c, expected a,b", b[0][0], b[0][1]) 386 } 387 } 388 389 func TestSendFDsNotEnabled(t *testing.T) { 390 server, client := socketPair(t, false) 391 defer server.Close() 392 defer client.Close() 393 394 // Write on the server. 395 w := server.Writer(true) 396 w.PackFDs(0, 1, 2) 397 if n, err := w.WriteVec([][]byte{{'a'}}); n != 1 || err != nil { 398 t.Fatalf("For server write, got n=%d err=%v, expected n=1 err=nil", n, err) 399 } 400 401 // Read on the client, without enabling FDs. 402 b := [][]byte{{'b'}} 403 r := client.Reader(true) 404 if n, err := r.ReadVec(b); n != 1 || err != nil { 405 t.Fatalf("For client read, got n=%d err=%v, expected n=1 err=nil", n, err) 406 } 407 if b[0][0] != 'a' { 408 t.Fatalf("Got bad read data, got %c, expected a", b[0][0]) 409 } 410 411 // Make sure the FDs are not received. 412 fds, err := r.ExtractFDs() 413 if len(fds) != 0 || err != nil { 414 t.Fatalf("Got fds=%v err=%v, expected len(fds)=0 err=nil", fds, err) 415 } 416 } 417 418 func sendFDs(t *testing.T, s *Socket, fds []int) { 419 w := s.Writer(true) 420 w.PackFDs(fds...) 421 if n, err := w.WriteVec([][]byte{{'a'}}); n != 1 || err != nil { 422 t.Fatalf("For write, got n=%d err=%v, expected n=1 err=nil", n, err) 423 } 424 } 425 426 func recvFDs(t *testing.T, s *Socket, enableSize int, origFDs []int) { 427 expected := len(origFDs) 428 429 // Count the number of FDs. 430 preEntries, err := ioutil.ReadDir("/proc/self/fd") 431 if err != nil { 432 t.Fatalf("Can't readdir, got err %v expected nil", err) 433 } 434 435 // Read on the client. 436 b := [][]byte{{'b'}} 437 r := s.Reader(true) 438 if enableSize >= 0 { 439 r.EnableFDs(enableSize) 440 } 441 if n, err := r.ReadVec(b); n != 1 || err != nil { 442 t.Fatalf("For client read, got n=%d err=%v, expected n=1 err=nil", n, err) 443 } 444 if b[0][0] != 'a' { 445 t.Fatalf("Got bad read data, got %c, expected a", b[0][0]) 446 } 447 448 // Count the new number of FDs. 449 postEntries, err := ioutil.ReadDir("/proc/self/fd") 450 if err != nil { 451 t.Fatalf("Can't readdir, got err %v expected nil", err) 452 } 453 if len(preEntries)+expected != len(postEntries) { 454 t.Errorf("Process fd count isn't right, expected %d got %d", len(preEntries)+expected, len(postEntries)) 455 } 456 457 // Make sure the FDs are there. 458 fds, err := r.ExtractFDs() 459 if len(fds) != expected || err != nil { 460 t.Fatalf("Got fds=%v err=%v, expected len(fds)=%d err=nil", fds, err, expected) 461 } 462 463 // Make sure they are different from the originals. 464 for i := 0; i < len(fds); i++ { 465 if fds[i] == origFDs[i] { 466 t.Errorf("Got original fd for index %d, expected different", i) 467 } 468 } 469 470 // Make sure they can be accessed as expected. 471 for i := 0; i < len(fds); i++ { 472 var st unix.Stat_t 473 if err := unix.Fstat(fds[i], &st); err != nil { 474 t.Errorf("fds[%d] can't be stated, got err %v expected nil", i, err) 475 } 476 } 477 478 // Close them off. 479 r.CloseFDs() 480 481 // Make sure the count is back to normal. 482 finalEntries, err := ioutil.ReadDir("/proc/self/fd") 483 if err != nil { 484 t.Fatalf("Can't readdir, got err %v expected nil", err) 485 } 486 if len(finalEntries) != len(preEntries) { 487 t.Errorf("Process fd count isn't right, expected %d got %d", len(preEntries), len(finalEntries)) 488 } 489 } 490 491 func TestFDsSingle(t *testing.T) { 492 server, client := socketPair(t, false) 493 defer server.Close() 494 defer client.Close() 495 496 sendFDs(t, server, []int{0}) 497 recvFDs(t, client, 1, []int{0}) 498 } 499 500 func TestFDsMultiple(t *testing.T) { 501 server, client := socketPair(t, false) 502 defer server.Close() 503 defer client.Close() 504 505 // Basic case, multiple FDs. 506 sendFDs(t, server, []int{0, 1, 2}) 507 recvFDs(t, client, 3, []int{0, 1, 2}) 508 } 509 510 // See TestSymmetric above. 511 func TestFDsSymmetric(t *testing.T) { 512 server, client := socketPair(t, false) 513 defer server.Close() 514 defer client.Close() 515 516 sendFDs(t, server, []int{0, 1, 2}) 517 recvFDs(t, client, 3, []int{0, 1, 2}) 518 } 519 520 func TestFDsReceiveLargeBuffer(t *testing.T) { 521 server, client := socketPair(t, false) 522 defer server.Close() 523 defer client.Close() 524 525 sendFDs(t, server, []int{0}) 526 recvFDs(t, client, 3, []int{0}) 527 } 528 529 func TestFDsReceiveSmallBuffer(t *testing.T) { 530 server, client := socketPair(t, false) 531 defer server.Close() 532 defer client.Close() 533 534 sendFDs(t, server, []int{0, 1, 2}) 535 536 // Per the spec, we may still receive more than the buffer. In fact, 537 // it'll be rounded up and we can receive two with a size one buffer. 538 recvFDs(t, client, 1, []int{0, 1}) 539 } 540 541 func TestFDsReceiveNotEnabled(t *testing.T) { 542 server, client := socketPair(t, false) 543 defer server.Close() 544 defer client.Close() 545 546 sendFDs(t, server, []int{0}) 547 recvFDs(t, client, -1, []int{}) 548 } 549 550 func TestFDsReceiveSizeZero(t *testing.T) { 551 server, client := socketPair(t, false) 552 defer server.Close() 553 defer client.Close() 554 555 sendFDs(t, server, []int{0}) 556 recvFDs(t, client, 0, []int{}) 557 } 558 559 func TestGetPeerCred(t *testing.T) { 560 server, client := socketPair(t, false) 561 defer server.Close() 562 defer client.Close() 563 564 want := &unix.Ucred{ 565 Pid: int32(os.Getpid()), 566 Uid: uint32(os.Getuid()), 567 Gid: uint32(os.Getgid()), 568 } 569 570 if got, err := client.GetPeerCred(); err != nil || !reflect.DeepEqual(got, want) { 571 t.Errorf("GetPeerCred() = %v, %v, want = %+v, %+v", got, err, want, nil) 572 } 573 } 574 575 func newClosedSocket() (*Socket, error) { 576 fd, err := unix.Socket(unix.AF_UNIX, unix.SOCK_STREAM, 0) 577 if err != nil { 578 return nil, err 579 } 580 581 s, err := NewSocket(fd) 582 if err != nil { 583 unix.Close(fd) 584 return nil, err 585 } 586 587 return s, s.Close() 588 } 589 590 func TestGetPeerCredFailure(t *testing.T) { 591 s, err := newClosedSocket() 592 if err != nil { 593 t.Fatalf("newClosedSocket got error %v want nil", err) 594 } 595 596 want := "bad file descriptor" 597 if _, err := s.GetPeerCred(); err == nil || err.Error() != want { 598 t.Errorf("s.GetPeerCred() = %v, want = %s", err, want) 599 } 600 } 601 602 func TestAcceptClosed(t *testing.T) { 603 name, err := randomFilename() 604 if err != nil { 605 t.Fatalf("Unable to generate file, got err %v expected nil", err) 606 } 607 608 ss, err := BindAndListen(name, false) 609 if err != nil { 610 t.Fatalf("Bind failed, got err %v expected nil", err) 611 } 612 613 if err := ss.Close(); err != nil { 614 t.Fatalf("Close failed, got err %v expected nil", err) 615 } 616 617 if _, err := ss.Accept(); err == nil { 618 t.Errorf("Accept on closed SocketServer, got err %v, want != nil", err) 619 } 620 } 621 622 func TestCloseAfterAcceptStart(t *testing.T) { 623 name, err := randomFilename() 624 if err != nil { 625 t.Fatalf("Unable to generate file, got err %v expected nil", err) 626 } 627 628 ss, err := BindAndListen(name, false) 629 if err != nil { 630 t.Fatalf("Bind failed, got err %v expected nil", err) 631 } 632 633 wg := sync.WaitGroup{} 634 wg.Add(1) 635 go func() { 636 defer wg.Done() 637 time.Sleep(50 * time.Millisecond) 638 if err := ss.Close(); err != nil { 639 t.Errorf("Close failed, got err %v expected nil", err) 640 } 641 }() 642 643 if _, err := ss.Accept(); err == nil { 644 t.Errorf("Accept on closed SocketServer, got err %v, want != nil", err) 645 } 646 647 wg.Wait() 648 } 649 650 func TestReleaseAfterAcceptStart(t *testing.T) { 651 name, err := randomFilename() 652 if err != nil { 653 t.Fatalf("Unable to generate file, got err %v expected nil", err) 654 } 655 656 ss, err := BindAndListen(name, false) 657 if err != nil { 658 t.Fatalf("Bind failed, got err %v expected nil", err) 659 } 660 661 wg := sync.WaitGroup{} 662 wg.Add(1) 663 go func() { 664 defer wg.Done() 665 time.Sleep(50 * time.Millisecond) 666 fd, err := ss.Release() 667 if err != nil { 668 t.Errorf("Release failed, got err %v expected nil", err) 669 } 670 unix.Close(fd) 671 }() 672 673 if _, err := ss.Accept(); err == nil { 674 t.Errorf("Accept on closed SocketServer, got err %v, want != nil", err) 675 } 676 677 wg.Wait() 678 } 679 680 func TestControlMessage(t *testing.T) { 681 for i := 0; i <= 10; i++ { 682 var want []int 683 for j := 0; j < i; j++ { 684 want = append(want, i+j+1) 685 } 686 687 var cm ControlMessage 688 cm.EnableFDs(i) 689 cm.PackFDs(want...) 690 got, err := cm.ExtractFDs() 691 if err != nil || !reflect.DeepEqual(got, want) { 692 t.Errorf("cm.ExtractFDs() = %v, %v, want = %v, %v", got, err, want, nil) 693 } 694 } 695 } 696 697 func benchmarkSendRecv(b *testing.B, packet bool) { 698 server, client, err := SocketPair(packet) 699 if err != nil { 700 b.Fatalf("SocketPair: got %v, wanted nil", err) 701 } 702 defer server.Close() 703 defer client.Close() 704 go func() { 705 buf := make([]byte, 1) 706 for i := 0; i < b.N; i++ { 707 n, err := server.Read(buf) 708 if n != 1 || err != nil { 709 b.Errorf("server.Read: got (%d, %v), wanted (1, nil)", n, err) 710 return 711 } 712 n, err = server.Write(buf) 713 if n != 1 || err != nil { 714 b.Errorf("server.Write: got (%d, %v), wanted (1, nil)", n, err) 715 return 716 } 717 } 718 }() 719 buf := make([]byte, 1) 720 b.ResetTimer() 721 for i := 0; i < b.N; i++ { 722 n, err := client.Write(buf) 723 if n != 1 || err != nil { 724 b.Fatalf("client.Write: got (%d, %v), wanted (1, nil)", n, err) 725 } 726 n, err = client.Read(buf) 727 if n != 1 || err != nil { 728 b.Fatalf("client.Read: got (%d, %v), wanted (1, nil)", n, err) 729 } 730 } 731 } 732 733 func BenchmarkSendRecvStream(b *testing.B) { 734 benchmarkSendRecv(b, false) 735 } 736 737 func BenchmarkSendRecvPacket(b *testing.B) { 738 benchmarkSendRecv(b, true) 739 }