socket.carbon 3.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105
  1. // Part of the Carbon Language project, under the Apache License v2.0 with LLVM
  2. // Exceptions. See /LICENSE for license information.
  3. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
  4. import Core library "io";
  5. import Cpp library "<arpa/inet.h>";
  6. import Cpp library "<netinet/in.h>";
  7. import Cpp library "<stdio.h>";
  8. import Cpp library "<string_view>";
  9. import Cpp library "<sys/socket.h>";
  10. import Cpp library "<unistd.h>";
  11. import Cpp inline '''
  12. #define SOCKADDR_IN_SIZE sizeof(struct sockaddr_in6)
  13. // Work around htons being a macro, not a function, on MacOS.
  14. // TODO: This should not be necessary once we can import function-like macros.
  15. inline unsigned short htons_wrap(unsigned short n) {
  16. return htons(n);
  17. }
  18. ''';
  19. fn Perror(s: str) {
  20. // TODO: Should we allow passing a string literal to a `const char*`
  21. // parameter?
  22. Cpp.perror(Cpp.std.data(s));
  23. }
  24. // Basic example of using POSIX networking functions via interop.
  25. //
  26. // Opens a socket listening on port 8081, waits for a single connection, then
  27. // reads a single chunk of up to 256 bytes from it and echoes it to the
  28. // terminal.
  29. fn Run() -> i32 {
  30. // TODO: `Cpp.SOCK_STREAM as i32` should probably be allowed.
  31. // TODO: Should this be an implicit conversion?
  32. let server_fd: i32 = Cpp.socket(Cpp.AF_INET6, (Cpp.SOCK_STREAM as u32) as i32, 0);
  33. if (server_fd == -1) {
  34. Perror("socket failed");
  35. return 1;
  36. }
  37. // TODO: Should be able to zero-initialize this with `= ()` or `= {}`.
  38. var address: Cpp.sockaddr_in6;
  39. Cpp.memset(&address, 0, Cpp.SOCKADDR_IN_SIZE);
  40. // TODO: Should this be valid without a cast? `AF_INET6` is defined to an
  41. // integer literal in glibc at least, but we import it as an `i32`.
  42. address.sin6_family = Cpp.AF_INET6 as Cpp.sa_family_t;
  43. // TODO: This leads to a link error referring to `in6addr_any.1`.
  44. // address.sin6_addr = Cpp.in6addr_any;
  45. let port: u16 = 8081;
  46. address.sin6_port = Cpp.htons_wrap(port);
  47. // TODO: Should be able to cast directly.
  48. let address_ptr: Cpp.sockaddr* =
  49. (&address as Cpp.void*) unsafe as Cpp.sockaddr*;
  50. // TODO: Should have an implicit conversion from
  51. // T* to Optional(const T*).
  52. // TODO: Should expose `sizeof` somehow.
  53. let bind_result: i32 = Cpp.bind(
  54. server_fd, address_ptr as const Cpp.sockaddr*, Cpp.SOCKADDR_IN_SIZE as u32
  55. );
  56. if (bind_result == -1) {
  57. Perror("bind failed");
  58. return 1;
  59. }
  60. if (Cpp.listen(server_fd, 1) == -1) {
  61. Perror("listen failed");
  62. return 1;
  63. }
  64. // TODO: Add a better `Core.Print`.
  65. Core.PrintStr("Server is listening on port ");
  66. Core.Print(port as i32);
  67. var addr_len: Cpp.socklen_t = 0;
  68. let socket_fd: i32 = Cpp.accept(
  69. server_fd,
  70. address_ptr,
  71. &addr_len
  72. );
  73. if (socket_fd == -1) {
  74. Perror("accept failed");
  75. return 1;
  76. }
  77. Core.PrintStr("Connection accepted!\n");
  78. var buffer: array(char, 256);
  79. let len: Cpp.ssize_t = Cpp.read(socket_fd, &buffer[0], 256);
  80. if (len < 0) {
  81. Perror("read failed");
  82. return 1;
  83. }
  84. Cpp.write(1, &buffer[0], len as Cpp.size_t);
  85. Cpp.close(socket_fd);
  86. Cpp.close(server_fd);
  87. return 0;
  88. }