tiny.stun.Builder
Defined in tiny.stun.
API (18)
Actions
Public operations.
appendAddressappendChangeRequestappendDecodedappendRawappendRawPaddedappendResponsePortappendUsernamefinishfinishFingerprintfinishIntegrityfinishIntegritySha256init
Fields and members
Public fields and members.
Source
Source: lib/stun/src/message.zig:266
zig
pub const Builder = struct { storage: []u8, capacity: Capacity, transaction_id: TransactionId, index: usize = header_bytes, attribute_count: u14 = 0, state: BuilderState = .attributes, pub fn init( storage: []u8, limits: Limits, class: Class, method: Method, transaction_id: TransactionId, ) EncodeError!Builder { const capacity = try Capacity.derive(limits); if (storage.len < capacity.message_bytes) return error.StorageTooSmall; var builder = Builder{ .storage = storage[0..capacity.message_bytes], .capacity = capacity, .transaction_id = transaction_id, }; std.mem.writeInt(u16, builder.storage[0..2], encodeType(method, class), .big); std.mem.writeInt(u16, builder.storage[2..4], 0, .big); std.mem.writeInt(u32, builder.storage[4..8], magic_cookie, .big); @memcpy(builder.storage[8..20], &transaction_id); return builder; } pub fn appendRaw( self: *Builder, type_code: u16, value: []const u8, ) EncodeError!void { const zeros = [_]u8{ 0, 0, 0 }; const padding_len = attribute.paddingLength(value.len); try self.appendRawPadded(type_code, value, zeros[0..padding_len]); } pub fn appendRawPadded( self: *Builder, type_code: u16, value: []const u8, padding: []const u8, ) EncodeError!void { if (self.state != .attributes) return error.InvalidBuilderState; if (isIntegrityOrFingerprint(type_code)) return error.UseFinishFunction; if (padding.len != attribute.paddingLength(value.len)) { return error.InvalidAttributePadding; } const region = try self.reserve(value.len, padding.len); std.mem.writeInt(u16, self.storage[region.start..][0..2], type_code, .big); std.mem.writeInt(u16, self.storage[region.start + 2 ..][0..2], @intCast(value.len), .big); @memcpy(self.storage[region.value_start..region.value_end], value); @memcpy(self.storage[region.value_end..region.end], padding); self.commit(region.end); } pub fn appendDecoded(self: *Builder, value: attribute.Attribute) EncodeError!void { try self.appendRawPadded(value.type_code, value.raw_value, value.padding); } pub fn appendUsername(self: *Builder, username: []const u8) EncodeError!void { _ = try integrity.shortTermKey(username); try self.appendRaw(@backingInt(attribute.Type.username), username); } pub fn appendAddress( self: *Builder, attribute_type: attribute.Type, address: attribute.Address, ) EncodeError!void { const xor_cookie: ?u32 = switch (attribute_type) { .xor_mapped_address => magic_cookie, .mapped_address, .alternate_server, .response_origin, .other_address => null, else => return error.InvalidAttributeType, }; var encoded: [20]u8 = undefined; const length = attribute.encodeAddress( &encoded, address, xor_cookie, self.transaction_id, ); try self.appendRaw(@backingInt(attribute_type), encoded[0..length]); } pub fn appendChangeRequest( self: *Builder, request: attribute.ChangeRequest, ) EncodeError!void { var encoded: [4]u8 = @splat(0); if (request.change_ip) encoded[3] |= 0x04; if (request.change_port) encoded[3] |= 0x02; try self.appendRaw(@backingInt(attribute.Type.change_request), &encoded); } pub fn appendResponsePort(self: *Builder, port: u16) EncodeError!void { var encoded: [2]u8 = undefined; std.mem.writeInt(u16, &encoded, port, .big); try self.appendRaw(@backingInt(attribute.Type.response_port), &encoded); } pub fn finishIntegrity(self: *Builder, key: []const u8) EncodeError!void { if (self.state != .attributes) return error.InvalidBuilderState; const region = try self.reserve(integrity.sha1_bytes, 0); writeAttributeHeader( self.storage, region.start, @backingInt(attribute.Type.message_integrity), integrity.sha1_bytes, ); @memset(self.storage[region.value_start..region.value_end], 0); const adjusted_len: u16 = @intCast(region.end - header_bytes); var digest: [integrity.sha1_bytes]u8 = undefined; integrity.hmacSha1Adjusted(&digest, self.storage, region.start, adjusted_len, key); @memcpy(self.storage[region.value_start..region.value_end], &digest); self.state = .sha1; self.commit(region.end); } pub fn finishIntegritySha256(self: *Builder, key: []const u8) EncodeError!void { if (self.state != .attributes and self.state != .sha1) { return error.InvalidBuilderState; } const region = try self.reserve(integrity.sha256_bytes, 0); writeAttributeHeader( self.storage, region.start, @backingInt(attribute.Type.message_integrity_sha256), integrity.sha256_bytes, ); @memset(self.storage[region.value_start..region.value_end], 0); const adjusted_len: u16 = @intCast(region.end - header_bytes); var digest: [integrity.sha256_bytes]u8 = undefined; integrity.hmacSha256Adjusted(&digest, self.storage, region.start, adjusted_len, key); @memcpy(self.storage[region.value_start..region.value_end], &digest); self.state = .sha256; self.commit(region.end); } pub fn finishFingerprint(self: *Builder) EncodeError!void { if (self.state == .fingerprint) return error.InvalidBuilderState; const region = try self.reserve(4, 0); writeAttributeHeader( self.storage, region.start, @backingInt(attribute.Type.fingerprint), 4, ); @memset(self.storage[region.value_start..region.value_end], 0); self.patchLength(region.end); const value = integrity.fingerprint(self.storage[0..region.start]); std.mem.writeInt(u32, self.storage[region.value_start..][0..4], value, .big); self.state = .fingerprint; self.commit(region.end); } pub fn finish(self: *Builder) []const u8 { self.patchLength(self.index); return self.storage[0..self.index]; } fn reserve(self: *Builder, value_len: usize, padding_len: usize) EncodeError!BuilderRegion { if (self.attribute_count == self.capacity.attributes) { return error.AttributeLimitExceeded; } if (value_len > std.math.maxInt(u16)) return error.MessageTooLarge; const value_start = std.math.add(usize, self.index, 4) catch return error.CapacityOverflow; const value_end = std.math.add(usize, value_start, value_len) catch return error.CapacityOverflow; const end = std.math.add(usize, value_end, padding_len) catch return error.CapacityOverflow; if (end > self.capacity.message_bytes) return error.MessageTooLarge; if (end - header_bytes > max_payload_bytes) return error.MessageTooLarge; return .{ .start = self.index, .value_start = value_start, .value_end = value_end, .end = end, }; } fn commit(self: *Builder, end: usize) void { std.debug.assert(end > self.index); std.debug.assert(end <= self.capacity.message_bytes); self.index = end; self.attribute_count += 1; self.patchLength(end); } fn patchLength(self: *Builder, end: usize) void { std.debug.assert(end >= header_bytes); std.debug.assert(end - header_bytes <= max_payload_bytes); std.mem.writeInt(u16, self.storage[2..4], @intCast(end - header_bytes), .big); }};Source: lib/stun/src/root.zig:31
zig
pub const Builder = message_mod.Builder;Audit
| Definitions | 13 |
|---|---|
| Public names | 13 |
| Members | 6 |
| Version | 26.7.0 |
| Revision | daab053ee433 |