╭─────────────╮ │scroll to top│ ╰─────────────╯ ╭ serve.zig ────────────────────────────────────────────────────╮ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ ╰───────────────────────────────────────────────────────────────╯
╭────╮ ╭ clone ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ╮ │http│ ssh │ │ ╰────╯ ╰ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ╯
209 const PortPolicy = enum { 210 // bind it anyway, so a restart isn't blocked by the last run's connections 211 // sitting in TIME_WAIT. on linux this also sets SO_REUSEPORT, so a server 212 // already holding the port ends up sharing it. 213 reuse, 214 // leave it to whoever holds it and take an OS-assigned port instead 215 fallback, 216 }; 217 218 fn listen(io: std.Io, listen_address: ListenAddress, policy: PortPolicy) !std.Io.net.Server { 219 const address = try std.Io.net.IpAddress.parseIp4(listen_address.host, listen_address.port); 220 return switch (policy) { 221 .reuse => try address.listen(io, .{ .reuse_address = true }), 222 .fallback => address.listen(io, .{}) catch |listen_err| switch (listen_err) { 223 error.AddressInUse => blk: { 224 const any_port = try std.Io.net.IpAddress.parseIp4(listen_address.host, 0); 225 break :blk try any_port.listen(io, .{}); 226 }, 227 else => |e| return e, 228 }, 229 }; 230 } 231 232 fn parseListenAddress(value: []const u8) !ListenAddress { 233 const colon = std.mem.lastIndexOfScalar(u8, value, ':') orelse return error.InvalidListenAddress; 234 if (colon == 0 or colon + 1 >= value.len) return error.InvalidListenAddress; 235 const port = try std.fmt.parseInt(u16, value[colon + 1 ..], 10); 236 return .{ .host = value[0..colon], .port = port }; 237 } 238