Meta: Add files to repository

This commit is contained in:
Alec Murphy 2025-03-25 07:32:23 -04:00
parent 80a0428b66
commit 39198164cd
1029 changed files with 78311 additions and 0 deletions

209
src/image/image.c vendored Normal file
View file

@ -0,0 +1,209 @@
#define STBI_WRITE_NO_STDIO
#define STB_IMAGE_WRITE_STATIC
#define STB_IMAGE_WRITE_IMPLEMENTATION
#define STB_IMAGE_IMPLEMENTATION
#define STBI_NO_LINEAR
#define STBI_NO_STDIO
#define STBI_NO_SIMD
#define STBI_NO_HDR
#include "stb_image.h"
#include "stb_image_write.h"
int main() { return 0; }
STBIDEF stbi_uc* image_load_gif_from_memory(stbi_uc const* buffer, int len,
int** delays, int* x, int* y,
int* z)
{
int comp;
return stbi_load_gif_from_memory(buffer, len, delays, x, y, z, &comp, 4);
}
/* dither.c: MIT License
Copyright (c) 2016 jonmortiboy
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
typedef struct RGB {
int r;
int g;
int b;
} RGB;
int imgw, imgh;
// Define the 4bit colour palette
int numCols = 16;
RGB cols4bit[] = {
{ 0, 0, 0 }, { 0, 0, 170 }, { 0, 170, 0 }, { 0, 170, 170 },
{ 170, 0, 0 }, { 170, 0, 170 }, { 170, 85, 0 }, { 170, 170, 170 },
{ 85, 85, 85 }, { 85, 85, 255 }, { 85, 255, 85 }, { 85, 255, 255 },
{ 255, 85, 85 }, { 255, 85, 255 }, { 255, 255, 85 }, { 255, 255, 255 }
};
RGB* cols = cols4bit;
RGB getRGB(uint32_t* pixels, int x, int y);
void setRGB(uint32_t* pixels, int x, int y, RGB rgb);
RGB difRGB(RGB from, RGB to);
RGB addRGB(RGB a, RGB b);
RGB divRGB(RGB rgb, double d);
RGB mulRGB(RGB rgb, double d);
RGB nearestRGB(RGB rgb, RGB* rgbs, int numRGBs);
double distRGB(RGB from, RGB to);
void render_4bit_floydstein(uint32_t* pixels, int width, int height);
RGB getRGB(uint32_t* pixels, int x, int y)
{
RGB rgb;
rgb.r = 0;
rgb.g = 0;
rgb.b = 0;
if (x < 0 || x >= imgw || y < 0 || y >= imgh)
return rgb;
rgb.r = (pixels[y * imgw + x] & 0xff);
rgb.g = (pixels[y * imgw + x] & 0xff00) >> 8;
rgb.b = (pixels[y * imgw + x] & 0xff0000) >> 16;
return rgb;
}
void setRGB(uint32_t* pixels, int x, int y, RGB rgb)
{
if (x < 0 || x >= imgw || y < 0 || y >= imgh)
return;
uint32_t alpha = pixels[y * imgw + x] & 0xff000000;
pixels[y * imgw + x] = alpha + (rgb.r) + (rgb.g << 8) + (rgb.b << 16);
}
RGB difRGB(RGB from, RGB to)
{
RGB dif;
dif.r = to.r - from.r;
dif.g = to.g - from.g;
dif.b = to.b - from.b;
return dif;
}
RGB addRGB(RGB a, RGB b)
{
RGB sum;
sum.r = a.r + b.r;
sum.g = a.g + b.g;
sum.b = a.b + b.b;
if (sum.r > 255)
sum.r = 255;
if (sum.r < 0)
sum.r = 0;
if (sum.g > 255)
sum.g = 255;
if (sum.g < 0)
sum.g = 0;
if (sum.b > 255)
sum.b = 255;
if (sum.b < 0)
sum.b = 0;
return sum;
}
RGB divRGB(RGB rgb, double d)
{
RGB div;
div.r = (int)((double)rgb.r / d);
div.g = (int)((double)rgb.g / d);
div.b = (int)((double)rgb.b / d);
return div;
}
RGB mulRGB(RGB rgb, double d)
{
RGB mul;
mul.r = (int)((double)rgb.r * d);
mul.g = (int)((double)rgb.g * d);
mul.b = (int)((double)rgb.b * d);
return mul;
}
double distRGB(RGB from, RGB to)
{
RGB dif = difRGB(from, to);
double dist = dif.r * dif.r + dif.g * dif.g + dif.b * dif.b;
return dist;
}
RGB nearestRGB(RGB rgb, RGB rgbs[], int numRGBs)
{
double dist = -1, tempDist;
RGB nearest;
int i;
for (i = 0; i < numRGBs; i++) {
tempDist = distRGB(rgb, rgbs[i]);
if (tempDist < dist || dist < 0) {
dist = tempDist;
nearest = rgbs[i];
}
}
return nearest;
}
void render_4bit_floydstein(uint32_t* pixels, int width, int height)
{
int i, x, y;
imgw = width;
imgh = height;
RGB rgb, nearest, rgberror;
for (i = 0; i < imgw * imgh; i++) {
rgb = getRGB(pixels, i % imgw, i / imgw);
nearest = nearestRGB(rgb, cols, numCols);
rgberror = difRGB(nearest, rgb);
rgberror = divRGB(rgberror, 16);
x = i % imgw;
y = i / imgw;
setRGB(pixels, x + 1, y,
addRGB(getRGB(pixels, x + 1, y), mulRGB(rgberror, 7)));
setRGB(pixels, x - 1, y + 1,
addRGB(getRGB(pixels, x - 1, y + 1), mulRGB(rgberror, 3)));
setRGB(pixels, x, y + 1,
addRGB(getRGB(pixels, x, y + 1), mulRGB(rgberror, 5)));
setRGB(pixels, x + 1, y + 1,
addRGB(getRGB(pixels, x + 1, y + 1), rgberror));
setRGB(pixels, i % imgw, i / imgw, nearest);
}
}

8634
src/image/stb_image.h vendored Normal file

File diff suppressed because it is too large Load diff

1807
src/image/stb_image_write.h vendored Normal file

File diff suppressed because it is too large Load diff

6
src/libtemple/ioport.h Normal file
View file

@ -0,0 +1,6 @@
u8 ioport_read_u8(u16 address);
u16 ioport_read_u16(u16 address);
u32 ioport_read_u32(u16 address);
void ioport_write_u8(u16 address, u8 value);
void ioport_write_u16(u16 address, u16 value);
void ioport_write_u32(u16 address, u32 value);

View file

@ -0,0 +1,77 @@
unsigned long ioport_read_u8(unsigned short address) { return 0; }
unsigned long ioport_read_u16(unsigned short address) { return 0; }
unsigned long ioport_read_u32(unsigned short address) { return 0; }
void ioport_write_u8(unsigned short address, unsigned char value) { }
void ioport_write_u16(unsigned short address, unsigned short value) { }
void ioport_write_u32(unsigned short address, unsigned int value) { }
bool os_blink(char const* frequency_as_string) { return 0; }
unsigned long os_call(unsigned long function_name, unsigned long arg) { return 0; }
unsigned int os_device_calloc(unsigned int size) { return 0; }
void os_exit() { }
char const* os_file_picker(char const* path, char const* glob) { return 0; }
char const* os_files_list(char const* path) { return 0; }
bool os_is_vm() { return 0; }
bool os_path_exists(char const* path) { return 0; }
void os_pc_speaker(char const* frequency_as_string) { }
unsigned long os_random() { return 0; }
unsigned long os_read_entire_file(char const* filename, long* size)
{
return 0;
}
void os_screenshot() { }
char const* os_to_uppercase(char const* input_string) { return 0; }
void os_write_entire_file(char const* filename, unsigned char* buffer,
long size) { }
long pci_find(long class_code) { return 0; }
unsigned long pci_read_u8(long bus, long device, long fun, long offset)
{
return 0;
}
unsigned long pci_read_u16(long bus, long device, long fun, long offset)
{
return 0;
}
unsigned long pci_read_u32(long bus, long device, long fun, long offset)
{
return 0;
}
void pci_write_u8(long bus, long device, long fun, long offset,
unsigned char value) { }
void pci_write_u16(long bus, long device, long fun, long offset,
unsigned short value) { }
void pci_write_u32(long bus, long device, long fun, long offset,
unsigned int value) { }
void time_busy(long duration) { }
long time_jiffies() { return 0; }
long time_now() { return 0; }
void time_sleep(long duration) { }

15
src/libtemple/os.h Normal file
View file

@ -0,0 +1,15 @@
bool os_blink(char const* frequency_as_string);
unsigned long os_call(unsigned long function_name, unsigned long arg);
unsigned int os_device_calloc(unsigned int size);
void os_exit();
char const* os_file_picker(char const* path, char const* glob);
char const* os_files_list(char const* path);
bool os_is_vm();
bool os_path_exists(char const* path);
void os_pc_speaker(char const* frequency_as_string);
unsigned long os_random();
u8* os_read_entire_file(char const* filename, i64* size);
void os_screenshot();
char const* os_to_uppercase(char const* input_string);
void os_write_entire_file(char const* filename, unsigned char* buffer,
i64 size);

10
src/libtemple/pci.h Normal file
View file

@ -0,0 +1,10 @@
long pci_find(long class_code);
unsigned long pci_read_u8(long bus, long device, long fun, long offset);
unsigned long pci_read_u16(long bus, long device, long fun, long offset);
unsigned long pci_read_u32(long bus, long device, long fun, long offset);
void pci_write_u8(long bus, long device, long fun, long offset,
unsigned char value);
void pci_write_u16(long bus, long device, long fun, long offset,
unsigned short value);
void pci_write_u32(long bus, long device, long fun, long offset,
unsigned int value);

4
src/libtemple/time.h Normal file
View file

@ -0,0 +1,4 @@
void time_busy(i64 duration);
i64 time_jiffies();
i64 time_now();
void time_sleep(i64 duration);

28
src/net/devices/virtio.h Normal file
View file

@ -0,0 +1,28 @@
struct virtio_queue_buf {
u64 address;
u32 length;
u16 flags;
u16 next;
};
struct virtio_avail {
u16 flags;
u16 index;
u16 ring[256];
u16 int_index;
};
struct virtio_used_item {
u32 index;
u32 length;
};
struct virtio_used {
u16 flags;
u16 index;
virtio_used_item ring[256];
u16 int_index;
};
struct virtio_queue {
virtio_queue_buf buffers[256];
virtio_avail available;
u8 padding[3578];
virtio_used used;
};

143
src/net/devices/virtio.jakt Normal file
View file

@ -0,0 +1,143 @@
import relative parent::os::os { OS }
import relative parent::os::pci { PCI, PCIDevice }
enum VirtIOConfig: u8 {
acknowledge = 1
driver = 2
driver_ok = 4
}
enum VirtIOReg: u16 {
host_features = 0
guest_features = 4
queue_page_frame_number = 8
queue_size = 12
queue_select = 14
queue_notify = 16
status = 18
isr = 19
config = 20
}
class VirtIO {
public pci_device: PCIDevice
public rq_index: i64
public rq_size: u16
public rq: u32
public tq_size: u16
public tq: u32
public fn rx_frame(mut this) throws -> [u8] {
mut frame: [u8] = []
mut queue_notify: bool = false
unsafe {
cpp {
"
#include <../../src/net/devices/virtio.h>
virtio_queue *rq = (virtio_queue*)this->rq;
i64 i = this->rq_index;
i64 used_index = rq->used.index;
if (used_index < i)
used_index += 0x10000;
if (used_index && i != used_index) {
virtio_used_item* item = rq->used.ring;
u8* buffer = (u8*)rq->buffers[item[i % 256].index + 1].address;
i64 length = item[i % 256].length - 10;
for (i64 j = 0; j < length; j++)
frame.push(buffer[j]);
this->rq_index = used_index % 0x10000;
rq->available.index++;
queue_notify = true;
}
"
}
}
if queue_notify {
.pci_device.io_write_u16(offset: VirtIOReg::queue_notify as! u16, value: 0)
}
return frame
}
public fn tx_frame(mut this, anon mut data: [u8]) throws {
mut size = data.size()
unsafe {
cpp {
"
#include <../../src/net/devices/virtio.h>
virtio_queue *tq = (virtio_queue*)this->tq;
int tq_idx = tq->available.index % 256;
int tq_idx2 = tq_idx % 128;
memset((u8*)tq->buffers[tq_idx2 * 2].address, 0, 10);
u8 *buffer = (u8*)tq->buffers[(tq_idx2 * 2) + 1].address;
for (int i = 0; i < size; i++)
buffer[i] = data[i];
tq->buffers[tq_idx2 * 2].length = 10;
tq->buffers[tq_idx2 * 2].flags = 1;
tq->buffers[tq_idx2 * 2].next = (tq_idx2 * 2) + 1;
tq->buffers[(tq_idx2 * 2) + 1].length = size;
tq->buffers[(tq_idx2 * 2) + 1].flags = 0;
tq->buffers[(tq_idx2 * 2) + 1].next = 0;
tq->available.ring[tq_idx] = tq_idx2 * 2;
tq->available.index++;
"
}
}
.pci_device.io_write_u16(offset: VirtIOReg::queue_notify as! u16, value: 1)
}
fn reset_device(this) {
.pci_device.io_write_u8(offset: VirtIOReg::status as! u16, value: 0)
}
fn found_driver(this) throws {
.pci_device.io_write_u8(offset: VirtIOReg::status as! u16,
value: .pci_device.io_read_u8(VirtIOReg::status as! u16) | VirtIOConfig::acknowledge as! u8 | VirtIOConfig::driver as! u8)
}
fn setup_rx_queue(mut this) throws {
.pci_device.io_write_u16(offset: VirtIOReg::queue_select as! u16, value: 0)
.rq_size = .pci_device.io_read_u16(VirtIOReg::queue_size as! u16)
.rq = OS::device_calloc(16384)
.pci_device.io_write_u32(offset: VirtIOReg::queue_page_frame_number as! u16, value: .rq / 4096)
}
fn setup_tx_queue(mut this) throws {
.pci_device.io_write_u16(offset: VirtIOReg::queue_select as! u16, value: 1)
.tq_size = .pci_device.io_read_u16(VirtIOReg::queue_size as! u16)
.tq = OS::device_calloc(16384)
.pci_device.io_write_u32(offset: VirtIOReg::queue_page_frame_number as! u16, value: .tq / 4096)
}
fn init_queue_buffers(this) {
unsafe {
cpp {
"
#include <../../src/net/devices/virtio.h>
virtio_queue *rq = (virtio_queue*)this->rq;
virtio_queue *tq = (virtio_queue*)this->tq;
for (int i = 0; i < 128; i++) {
rq->buffers[i * 2].address = (u64)calloc(1, 16);
rq->buffers[i * 2].length = 10;
rq->buffers[i * 2].flags = 3;
rq->buffers[i * 2].next = (i * 2) + 1;
rq->buffers[(i * 2) + 1].address = (u64)calloc(1, 2048);
rq->buffers[(i * 2) + 1].length = 2048;
rq->buffers[(i * 2) + 1].flags = 2;
rq->buffers[(i * 2) + 1].next = 0;
rq->available.ring[i] = i * 2;
rq->available.ring[i + 128] = i * 2;
tq->buffers[i * 2].address = (u64)calloc(1, 16);
tq->buffers[(i * 2) + 1].address = (u64)calloc(1, 2048);
}
rq->available.index = 1;
"
}
}
}
fn init_ok(this) throws {
.pci_device.io_write_u8(offset: VirtIOReg::status as! u16,
value: .pci_device.io_read_u8(VirtIOReg::status as! u16) | VirtIOConfig::driver_ok as! u8)
.pci_device.io_write_u16(offset: VirtIOReg::queue_notify as! u16, value: 0)
}
public fn init(mut this) throws {
.reset_device()
.found_driver()
.setup_rx_queue()
.setup_tx_queue()
.init_queue_buffers()
.init_ok()
}
}

350
src/net/lib/json.jakt Normal file
View file

@ -0,0 +1,350 @@
/// Expect:
/// - output: "JsonValue::JsonArray([JsonValue::Object([\"id\": JsonValue::Number(0.5), \"displayName\": JsonValue::JsonString(\"Air\"), \"name\": JsonValue::JsonString(\"air\"), \"hardness\": JsonValue::Number(3.9), \"resistance\": JsonValue::Number(0), \"minStateId\": JsonValue::Number(0), \"maxStateId\": JsonValue::Number(0), \"states\": JsonValue::JsonArray([])])])\n"
enum JsonValue {
Null
Bool(bool)
Number(f64)
// FIXME: This variant should be called String
JsonString(String)
// FIXME: This variant should be called Array
JsonArray([JsonValue])
Object([String:JsonValue])
}
fn is_whitespace(anon c: u8) -> bool {
return match c {
b'\t' | b'\n' | b'\r' | b' ' => true
else => false
}
}
class JsonParser {
input: String
index: usize
public fn construct(input: String) throws -> JsonParser {
return JsonParser(input, index: 0)
}
fn eof(this) -> bool {
return .index >= .input.length()
}
public fn parse(mut this) throws -> JsonValue {
// FIXME: Jakt::JsonParser ignores trailing whitespace for some reason.
let value = .parse_helper()
if not .eof() {
// FIXME: "Didn't consume all input"
throw Error::from_errno(9000)
}
return value
}
fn skip_whitespace(mut this) {
while not .eof() {
if not is_whitespace(.input.byte_at(.index)) {
break
}
.index++
}
}
fn consume_and_unescape_string(mut this) throws -> String {
if not .consume_specific(b'"') {
// FIXME: "Expected '"'
throw Error::from_errno(9007)
}
mut builder = StringBuilder::create()
loop {
mut ch = 0u8
mut peek_index = .index
while peek_index < .input.length() {
ch = .input.byte_at(peek_index)
if ch == b'"' or ch == b'\\' {
break
}
// FIXME: This is is_ascii_c0_control()
if ch < 0x20 {
// FIXME: "Error while parsing string"
throw Error::from_errno(9008)
}
peek_index++
}
while peek_index != .index {
builder.append(.input.byte_at(.index))
.index++
}
if .eof() {
break
}
if ch == b'"' {
break
}
if ch != b'\\' {
builder.append(.consume())
continue
}
.ignore()
match .peek() {
b'"' | b'/' | b'\\' | b'n' | b'r' | b't' | b'b' | b'f' => {
let ch = .consume()
builder.append(match ch {
b'n' => b'\n'
b'r' => b'\r'
b't' => b'\t'
b'b' => b'\b'
b'f' => b'\f'
else => ch
})
}
b'u' => {
eprintln("FIXME: Implement unicode literals")
abort()
}
else => {
// FIXME: "Error while parsing string"
throw Error::from_errno(9009)
}
}
}
if not .consume_specific(b'"') {
// FIXME: "Expected '"'"
throw Error::from_errno(9010)
}
return builder.to_string()
}
fn ignore(mut this) {
.index++
}
fn peek(this) -> u8 {
if .eof() {
return 0
}
return .input.byte_at(.index)
}
fn consume(mut this) -> u8 {
let ch = .peek()
.index++
return ch
}
fn consume_specific(mut this, anon expected: u8) -> bool {
if .peek() != expected {
return false
}
.index++
return true
}
fn parse_helper(mut this) throws -> JsonValue {
.skip_whitespace()
return match .peek() {
b'{' => .parse_object()
b'[' => .parse_array()
b'"' => .parse_string()
b'-' => .parse_number()
b'0' | b'1' | b'2' | b'3' | b'4' | b'5' | b'6' | b'7' | b'8' | b'9' => .parse_number()
b'f' => .parse_false()
b't' => .parse_true()
b'n' => .parse_null()
else => .parse_failure(error_message: "Unexpected character")
}
}
fn parse_failure(this, error_message: String) throws -> JsonValue {
throw Error::from_errno(9001)
}
fn parse_array(mut this) throws -> JsonValue {
mut array: [JsonValue] = []
if (not .consume_specific(b'[')) {
// Expected '['
throw Error::from_errno(9014)
}
loop {
.skip_whitespace()
if .peek() == b']' {
break
}
array.push(.parse_helper())
.skip_whitespace()
if .peek() == b']' {
break
}
if not .consume_specific(b',') {
// Expected ','
throw Error::from_errno(9014)
}
.skip_whitespace()
if .peek() == b']' {
// Unexpected ']'
throw Error::from_errno(9014)
}
}
if not .consume_specific(b']') {
// Expected ']'
throw Error::from_errno(9015)
}
return JsonValue::JsonArray(array)
}
fn parse_object(mut this) throws -> JsonValue {
if not .consume_specific(b'{') {
// FIXME: "Expected '{'"
throw Error::from_errno(9002)
}
mut values: [String:JsonValue] = [:]
loop {
.skip_whitespace()
if .peek() == b'}' {
break
}
.skip_whitespace()
let key = .consume_and_unescape_string()
.skip_whitespace()
if not .consume_specific(b':') {
// FIXME: "Expected ':'"
throw Error::from_errno(9003)
}
.skip_whitespace()
let value = .parse_helper()
// FIXME: This should say `values[key] = value`, but the compiler doesn't wrap it in TRY()
values.set(key, value)
.skip_whitespace()
if .peek() == b'}' {
break
}
if not .consume_specific(b',') {
// FIXME: "Expected ','"
throw Error::from_errno(9004)
}
.skip_whitespace()
if .peek() == b'}' {
// FIXME: "Unexpected '}'"
throw Error::from_errno(9005)
}
}
if not .consume_specific(b'}') {
// FIXME: "Expected '}'"
throw Error::from_errno(9006)
}
return JsonValue::Object(values)
}
fn char_to_f64(anon num: u8) throws -> f64 {
// FIXME 1: Shouldn't need this function at all
// FIXME 2: Shouldn't need return in else branch
return match num {
0u8 => 0.0
1u8 => 1.0
2u8 => 2.0
3u8 => 3.0
4u8 => 4.0
5u8 => 5.0
6u8 => 6.0
7u8 => 7.0
8u8 => 8.0
9u8 => 9.0
else => {
// FIXME: "Unexpected number"
throw Error::from_errno(9017)
}
}
}
fn parse_number(mut this) throws -> JsonValue {
// FIXME: This implementation doesn't match JsonParser.cpp
let is_negative = .consume_specific(b'-')
mut decimal_start_index: usize? = None
mut value = 0.0
while not .eof() {
let ch = .peek()
if ch == b'.' {
if decimal_start_index.has_value() {
// FIXME: "Unexpected '.'"
throw Error::from_errno(9016)
}
decimal_start_index = .index++
continue
} else if not (ch >= b'0' and ch <= b'9') {
break
}
if not decimal_start_index.has_value() {
value *= 10.0
value += char_to_f64(ch - b'0')
} else {
mut num = char_to_f64(ch - b'0')
// FIXME: This should really be: `value += pow(10, -decimal_place)*num`, but: there's no pow function and you can't multiply float by usize
let decimal_place = .index - decimal_start_index.value()
for i in 0..decimal_place {
num /= 10.0
}
value += num
}
.index++
}
if is_negative {
value *= -1.0
}
return JsonValue::Number(value)
}
fn parse_string(mut this) throws -> JsonValue {
return JsonValue::JsonString(.consume_and_unescape_string())
}
fn parse_false(mut this) throws -> JsonValue {
if (.consume() != b'f' or .consume() != b'a' or .consume() != b'l' or .consume() != b's' or .consume() != b'e') {
// FIXME: "Expected 'false'"
throw Error::from_errno(9011)
}
return JsonValue::Bool(false)
}
fn parse_true(mut this) throws -> JsonValue {
if (.consume() != b't' or .consume() != b'r' or .consume() != b'u' or .consume() != b'e') {
// FIXME: "Expected 'true'"
throw Error::from_errno(9012)
}
return JsonValue::Bool(true)
}
fn parse_null(mut this) throws -> JsonValue {
if (.consume() != b'n' or .consume() != b'u' or .consume() != b'l' or .consume() != b'l') {
// FIXME: "Expected 'null'"
throw Error::from_errno(9013)
}
return JsonValue::Null
}
}
// fn parse_json(input: String) throws -> JsonValue {
// mut parser = JsonParser::construct(input)
// return parser.parse()
// }
//
// fn main() {
// let value = parse_json(input: "[{\"id\":0.5,\"displayName\":\"Air\",\"name\":\"air\",\"hardness\":3.9,\"resistance\":0,\"minStateId\":0,\"maxStateId\":0,\"states\":[]}]")
// println("{}", value)
// }

147
src/net/lib/util.jakt Normal file
View file

@ -0,0 +1,147 @@
import relative parent::os::os { OS }
struct Util {
fn get_address_u32_from_ipv4_u8_array(anon array: [u8]) -> u32 {
if array.size() != 4 {
return 0
}
mut address: u32 = (array[3] as! u32 & 0xff) as! u32
address += ((array[2] as! u32 & 0xff) << 8) as! u32
address += ((array[1] as! u32 & 0xff) << 16) as! u32
address += ((array[0] as! u32 & 0xff) << 24) as! u32
return address
}
fn get_hexadecimal_string_from_ipv4_u8_array(anon array: [u8]) throws -> String {
mut s = StringBuilder::create()
unsafe {
cpp {
"char *chars = (char*)calloc(32, 1);
sprintf(chars, \"%02x%02x%02x%02x\", array[0], array[1], array[2], array[3]);
s.append_c_string(chars);
delete(chars);"
}
}
return s.to_string()
}
fn get_md5_string_from_string(anon s: String) throws -> String {
mut sb = StringBuilder::create()
unsafe {
cpp {
"
char* md5 = (char*)os_call((u64)\"@saubari_get_md5_string_from_string\", (u64)s.characters());
sb.append_c_string(md5);
delete(md5);
"
}
}
return sb.to_string()
}
fn get_ipv4_u8_array_from_address_string(anon s: String) throws -> [u8] {
mut address: [u8] = []
let octet_strings = s.split(c'.')
for octet_string in octet_strings {
unsafe {
cpp {
"auto value = octet_string.to_number<u32>();
if (value.has_value()) {
auto result = value.release_value();
address.push(result & 0xff);
}"
}
}
}
return address
}
fn get_ipv4_u8_array_from_address_u32(anon addr: u32) throws -> [u8] {
mut address: [u8] = []
// let source_address: [u8] = [ipv4_packet[12], ipv4_packet[13], ipv4_packet[14], ipv4_packet[15]]
address.push(((addr >> 24) & 0xff) as! u8)
address.push(((addr >> 16) & 0xff) as! u8)
address.push(((addr >> 8) & 0xff) as! u8)
address.push((addr & 0xff) as! u8)
return address
}
fn get_string_from_u8_array(anon array: [u8]) throws -> String {
mut s = StringBuilder::create()
unsafe {
cpp {
"for (int i = 0; i < array.size(); i++) {
s.append(array[i]);
}"
}
}
return s.to_string()
}
fn get_u16_from_u8_array(anon array: [u8], anon offset: i64) -> u16{
return (array[offset] as! u16 << 8) + array[offset + 1] as! u16
}
fn get_u16_from_u8_arrayslice(anon array: ArraySlice<u8>, anon offset: i64) -> u16{
return (array[offset] as! u16 << 8) + array[offset + 1] as! u16
}
fn push_string_to_u8_array(anon mut array: [u8], anon s: String) throws {
for i in 0..s.length() {
unsafe {
cpp {
"array.push(s.characters()[i]);"
}
}
}
}
fn push_u16_to_u8_array(anon mut array: [u8], anon value: u16) throws {
array.push((value >> 8) as! u8)
array.push((value & 0xff) as! u8)
}
fn push_u32_to_u8_array(anon mut array: [u8], anon value: u32) throws {
mut val_u32_to_u8: u32 = 0
val_u32_to_u8 = (value >> 24) & 0xff
array.push(val_u32_to_u8 as! u8)
val_u32_to_u8 = (value >> 16) & 0xff
array.push(val_u32_to_u8 as! u8)
val_u32_to_u8 = (value >> 8) & 0xff
array.push(val_u32_to_u8 as! u8)
array.push((value & 0xff) as! u8)
}
fn get_dictionary_from_json_file(anon json_file: String) throws -> [String:String] {
mut dictionary: [String:String] = Dictionary()
let json_bytes = OS::read_entire_file(json_file)
let json_string = get_string_from_u8_array(json_bytes)
unsafe {
cpp {
"auto json = JsonValue::from_string(json_string).value();
auto const& object = json.as_object();
object.for_each_member([&]([[maybe_unused]] auto& property_name, [[maybe_unused]] const JsonValue& property_value) {
dictionary.set(property_name, property_value.deprecated_to_byte_string());
});"
}
}
return dictionary
}
fn get_dictionary_from_string(anon s: String) throws -> [String:String] {
mut dictionary: [String:String] = Dictionary()
unsafe {
cpp {
"auto json = JsonValue::from_string(s).value();
auto const& object = json.as_object();
object.for_each_member([&]([[maybe_unused]] auto& property_name, [[maybe_unused]] const JsonValue& property_value) {
dictionary.set(property_name, property_value.deprecated_to_byte_string());
});"
}
}
return dictionary
}
fn string_from_file(anon filepath: String) throws -> String {
if filepath.is_empty() or not OS::path_exists(filepath) {
return ""
}
let array = OS::read_entire_file(filepath)
mut s = StringBuilder::create()
unsafe {
cpp {
"for (int i = 0; i < array.size(); i++) {
s.append(array[i]);
}"
}
}
return s.to_string()
}
}

173
src/net/net.jakt Normal file
View file

@ -0,0 +1,173 @@
import devices::virtio { VirtIO, VirtIOReg }
import lib::util { Util }
import os::os { OS }
import os::pci { PCI, PCIDevice }
import os::time { Time }
import tcpip { TCPIP }
class NetDevices {
public virtio: VirtIO
public fn create(pci_device: PCIDevice) throws -> NetDevices {
return NetDevices(
virtio: VirtIO(pci_device, rq_index: 0, rq_size: 0, rq: 0, tq_size: 0, tq: 0)
)
}
}
class Net {
public device: NetDevices
public mac_address: [u8]
public tcpip: TCPIP
public pci_device: PCIDevice
public fn init(config: [String:String]) throws -> Net {
let pci_device = PCI::find_device_by_class_code(0x020000)
mut net = Net(
device: NetDevices::create(pci_device)
mac_address: []
tcpip: TCPIP(
ipv4_address: Util::get_ipv4_u8_array_from_address_string(config["tcpip.ipv4_address"])
ipv4_netmask: Util::get_ipv4_u8_array_from_address_string(config["tcpip.ipv4_netmask"])
ipv4_network: Util::get_ipv4_u8_array_from_address_string(config["tcpip.ipv4_network"])
ipv4_gateway: Util::get_ipv4_u8_array_from_address_string(config["tcpip.ipv4_gateway"])
dns_server_address: Util::get_ipv4_u8_array_from_address_string(config["tcpip.ipv4_dns_server_address"])
dns_server_port: config["tcpip.ipv4_dns_server_port"].to_number<u32>().value() as! u16
mss_size: config["tcpip.mss_size"].to_number<u32>().value() as! u16
tx_queue: []
ttl: 64
arp_cache: Dictionary()
bound_sockets: Dictionary()
dns_cache: Dictionary()
tcp_sessions: []
pending_dns_lookups: Dictionary()
pending_dns_cached_entries: Dictionary()
pending_icmp_requests: Dictionary()
timestamp_last_arp_request: 0
rx_bytes: 0
rx_frames: 0
tx_bytes: 0
tx_frames: 0
)
pci_device
)
if net.pci_device.vendor_id() == 0x1af4 and net.pci_device.device_id() == 0x1000 {
println("[net] Found device: virtio-net, QEMU")
for i in 0u16..6u16 {
net.mac_address.push(net.pci_device.io_read_u8(VirtIOReg::config as! u16 + i))
}
net.device.virtio.init()
return net
}
println("[net] No supported vendor ids found")
OS::exit()
return net
}
fn process_ethernet_frame(mut this, anon frame: [u8]) throws {
let ethertype: u16 = (frame[12] as! u16 * 256) + frame[13] as! u16
match ethertype {
0x0806 => {
//println("ARP")
.tcpip.process_arp_packet(.mac_address, frame)
}
0x0800 => {
//println("IPv4")
.tcpip.process_ipv4_packet(.mac_address, frame)
}
0x86dd => {
//.tcpip.process_ipv6_packet(frame)
}
0x8035 => {
//.tcpip.process_rarp_packet(frame)
}
else => {
// unsupported
}
}
}
public fn process_events(mut this) throws {
mut received_frame = .rx_frame()
if received_frame.size() > 0 {
.tcpip.rx_bytes += received_frame.size() as! u64
.tcpip.rx_frames++
.process_ethernet_frame(received_frame)
}
.tcpip.tcp_transmit_pending_data_for_existing_sessions()
for frame in .tcpip.tx_queue {
.tx_frame(frame)
}
if .tcpip.tx_queue.size() > 0 {
.tcpip.tx_queue.shrink(0)
}
.tcpip.tcp_process_bind_request()
.tcpip.tcp_process_client_socket_request(.mac_address)
.tcpip.tcp_process_client_received_data()
.tcpip.tcp_process_client_send_requests(.mac_address)
.tcpip.dns_process_client_request(.mac_address)
.tcpip.icmp_process_client_request(.mac_address)
.tcpip.netinfo_process_client_request(.mac_address)
}
fn rx_frame(mut this) throws -> [u8] {
mut frame: [u8] = []
if .pci_device.vendor_id() == 0x1af4 and .pci_device.device_id() == 0x1000 {
frame = .device.virtio.rx_frame()
}
return frame
}
fn tx_frame(mut this, anon mut data: [u8]) throws {
if data.size() < 1 {
return
}
while data.size() < 60 {
data.push(0u8)
}
.tcpip.tx_bytes += data.size() as! u64
.tcpip.tx_frames++
if .pci_device.vendor_id() == 0x1af4 and .pci_device.device_id() == 0x1000 {
.device.virtio.tx_frame(data)
}
}
}
fn main() {
println("$WW,1$")
mut config = Util::get_dictionary_from_json_file("M:/System/Config/Net.json")
mut net = Net::init(config)
println("[net] PCI device is {}", net.pci_device)
print("[net] MAC address is ")
for i in 0u16..5u16 {
print("{:0>2x}:", net.mac_address[i])
}
println("{:0>2x}", net.mac_address[5])
print("[net] IPv4 address is ")
for i in 0u16..3u16 {
print("{:d}.", net.tcpip.ipv4_address[i])
}
println("{:d}", net.tcpip.ipv4_address[3])
println(" ")
// Update the ARP cache entry for IPv4 gateway address
net.tcpip.send_arp_request(net.mac_address, net.tcpip.ipv4_gateway)
mut prev_rx_frames = net.tcpip.rx_frames
mut prev_tx_frames = net.tcpip.tx_frames
mut prev_jiffies = Time::jiffies()
while true {
net.process_events()
if (prev_rx_frames != net.tcpip.rx_frames) or (prev_tx_frames != net.tcpip.tx_frames) {
prev_rx_frames = net.tcpip.rx_frames
prev_tx_frames = net.tcpip.tx_frames
prev_jiffies = Time::jiffies()
}
if Time::jiffies() < prev_jiffies + 250 {
Time::sleep(0)
} else {
Time::sleep(1)
}
}
OS::exit()
}

29
src/net/os/ioport.jakt Normal file
View file

@ -0,0 +1,29 @@
import extern c "ioport.h" {
extern fn ioport_read_u8(address: u16) -> u8
extern fn ioport_read_u16(address: u16) -> u16
extern fn ioport_read_u32(address: u16) -> u32
extern fn ioport_write_u8(address: u16, value: u8)
extern fn ioport_write_u16(address: u16, value: u16)
extern fn ioport_write_u32(address: u16, value: u32)
}
struct IOPort {
fn read_u8(anon address: u16) throws -> u8 {
return ioport_read_u8(address)
}
fn read_u16(anon address: u16) throws -> u16 {
return ioport_read_u16(address)
}
fn read_u32(anon address: u16) throws -> u32 {
return ioport_read_u32(address)
}
fn write_u8(address: u16, value: u8) {
return ioport_write_u8(address, value)
}
fn write_u16(address: u16, value: u16) {
return ioport_write_u16(address, value)
}
fn write_u32(address: u16, value: u32) {
return ioport_write_u32(address, value)
}
}

154
src/net/os/os.jakt Normal file
View file

@ -0,0 +1,154 @@
import extern c "os.h" {
extern fn os_blink(frequency: raw c_char) -> bool
extern fn os_call(function_name: u64, arg: u64) -> u64
extern fn os_device_calloc(size: u32) -> u32
extern fn os_exit()
extern fn os_file_picker(path: raw c_char, glob: raw c_char)
extern fn os_files_list(path: raw c_char)
extern fn os_is_vm() -> bool
extern fn os_path_exists(anon path: raw c_char) -> bool
extern fn os_pc_speaker(frequency: raw c_char)
extern fn os_random() -> u64
extern fn os_screenshot()
extern fn os_to_uppercase(anon input_string: raw c_char) -> raw c_char
}
struct OS {
fn blink(frequency: f64 = 2.5) throws -> bool {
let frequency_as_string = format("{}", frequency)
return os_blink(frequency: frequency_as_string.c_string())
}
fn call(anon function_name: String, anon arg: String) throws -> u64 {
mut res: u64 = 0
unsafe {
cpp {
"
res = os_call((u64)function_name.characters(), (u64)arg.characters());
"
}
}
return res
}
fn device_calloc(anon size: u32) throws -> u32 {
return os_device_calloc(size)
}
fn device_copy_buffer(anon buffer: [u8]) -> u32 {
mut address: u32 = 0
mut size = buffer.size()
unsafe {
cpp {
"u8 *data = (u8*)os_device_calloc(size);
for (int i = 0; i < size; i++)
data[i] = buffer[i];
address = (uintptr_t)data;"
}
}
return address
}
fn exit() {
os_exit()
}
fn file_picker(path: String, glob: String) throws -> String {
mut s = StringBuilder::create()
unsafe {
cpp {
"char const *chars = os_file_picker(path.characters(), glob.characters());
s.append_c_string(chars);
delete(chars);"
}
}
return s.to_string()
}
fn files_list(path: String) throws -> [String] {
mut s = StringBuilder::create()
unsafe {
cpp {
"char const *chars = os_files_list(path.characters());
if (chars) {
s.append_c_string(chars);
delete(chars);
}"
}
}
return s.to_string().split(c'|')
}
fn path_exists(anon path: String) -> bool {
return os_path_exists(path.c_string())
}
fn is_vm() -> bool {
return os_is_vm()
}
fn pc_speaker(frequency: f64) throws {
let frequency_as_string = format("{}", frequency)
os_pc_speaker(frequency: frequency_as_string.c_string())
}
fn put_char(ch: u8) {
unsafe {
cpp {
"putchar(ch);"
}
}
}
fn random() -> u64 {
return os_random()
}
fn read_entire_file(anon filename: String) throws -> [u8] {
mut size = 0
mut buffer: [u8] = []
unsafe {
cpp {
"u8 *data = os_read_entire_file(filename.characters(), &size);
for (int i = 0; i < size; i++)
buffer.push(data[i]);
free(data);"
}
}
return buffer
}
fn read_device_memory(address: u32, size: i64) throws -> [u8] {
mut buffer: [u8] = [];
unsafe {
cpp {
"u8 *device_memory = (u8*)address;
for (int i = 0; i < size; i++)
buffer.push(device_memory[i]);"
}
}
return buffer
}
fn read_u16_from_device_memory(anon address: u32) throws -> u16 {
mut value: u16 = 0
unsafe {
cpp {
"value = *(u16*)address;"
}
}
return value
}
fn screenshot() {
os_screenshot()
}
fn to_uppercase(anon input_string: String) throws -> String {
mut s = StringBuilder::create()
unsafe {
cpp {
"char const *chars = os_to_uppercase(input_string.characters());
s.append_c_string(chars);
delete(chars);"
}
}
return s.to_string()
}
fn write_entire_file(filename: String, buffer: [u8]) {
mut size = buffer.size()
unsafe {
cpp {
"unsigned char *data = (unsigned char *)malloc(size);
for (int i = 0; i < size; i++)
data[i] = buffer[i];
os_write_entire_file(filename.characters(), data, size);
free(data);"
}
}
}
}

103
src/net/os/pci.jakt Normal file
View file

@ -0,0 +1,103 @@
import ioport { IOPort }
import extern c "pci.h" {
extern fn pci_find(anon class_code: i64) -> i64
extern fn pci_read_u8(anon bus: i64, anon device: i64, anon fun: i64, anon offset: i64) -> u8
extern fn pci_read_u16(anon bus: i64, anon device: i64, anon fun: i64, anon offset: i64) -> u16
extern fn pci_read_u32(anon bus: i64, anon device: i64, anon fun: i64, anon offset: i64) -> u32
extern fn pci_write_u8(anon bus: i64, anon device: i64, anon fun: i64, anon offset: i64, anon value: u8)
extern fn pci_write_u16(anon bus: i64, anon device: i64, anon fun: i64, anon offset: i64, anon value: u16)
extern fn pci_write_u32(anon bus: i64, anon device: i64, anon fun: i64, anon offset: i64, anon value: u32)
}
struct PCIDevice {
bus: i64
device: i64
fun: i64
pci_vendor_id: u16
pci_device_id: u16
bar: [u32]
public fn enable_bus_master(mut this) {
.set_command(.command() | 0x4)
}
public fn read_u8(this, anon offset: i64) -> u8 {
return pci_read_u8(.bus, .device, .fun, offset)
}
public fn read_u16(this, anon offset: i64) -> u16 {
return pci_read_u16(.bus, .device, .fun, offset)
}
public fn read_u32(this, anon offset: i64) -> u32 {
return pci_read_u32(.bus, .device, .fun, offset)
}
public fn write_u8(this, offset: i64, value: u8) {
pci_write_u8(.bus, .device, .fun, offset, value)
}
public fn write_u16(this, offset: i64, value: u16) {
pci_write_u16(.bus, .device, .fun, offset, value)
}
public fn write_u32(this, offset: i64, value: u32) {
pci_write_u32(.bus, .device, .fun, offset, value)
}
public fn io_read_u8(this, anon offset: u16) throws -> u8 {
return IOPort::read_u8(.bar[0] as! u16 + offset)
}
public fn io_read_u16(this, anon offset: u16) throws -> u16 {
return IOPort::read_u16(.bar[0] as! u16 + offset)
}
public fn io_read_u32(this, anon offset: u16) throws -> u32 {
return IOPort::read_u32(.bar[0] as! u16 + offset)
}
public fn io_write_u8(this, offset: u16, value: u8) {
IOPort::write_u8(address: .bar[0] as! u16 + offset, value)
}
public fn io_write_u16(this, offset: u16, value: u16) {
IOPort::write_u16(address: .bar[0] as! u16 + offset, value)
}
public fn io_write_u32(this, offset: u16, value: u32) {
IOPort::write_u32(address: .bar[0] as! u16 + offset, value)
}
public fn vendor_id(this) -> u16 {
return .pci_vendor_id
}
public fn device_id(this) -> u16 {
return .pci_device_id
}
public fn command(this) -> u16 {
return pci_read_u16(.bus, .device, .fun, 0x4)
}
public fn set_command(this, anon value: u16) {
pci_write_u16(.bus, .device, .fun, offset: 0x4, value)
}
public fn status(this) -> u16 {
return pci_read_u16(.bus, .device, .fun, 0x6)
}
}
fn lookup_bar(bus: i64, device: i64, fun: i64, anon index: i64) -> u32 {
if index < 0 or index > 5 {
return 0xFFFFFFFF
}
return pci_read_u32(bus, device, fun, 0x10 + (index * 4)) & 0xFFFFFFFC
}
struct PCI {
public fn find_device_by_class_code(anon class_code: i64) throws -> PCIDevice {
let result = pci_find(class_code)
if result < 0 {
eprintln("error: device not found")
throw Error::from_errno(1)
}
let bus = (result >> 16) & 0xff
let device = (result >> 8) & 0xff
let fun = result & 0xff
let pci_vendor_id = pci_read_u16(bus, device, fun, 0x0)
let pci_device_id = pci_read_u16(bus, device, fun, 0x2)
mut bar: [u32] = []
for i in 0..5 {
bar.push(lookup_bar(bus, device, fun, i))
}
return PCIDevice(bus, device, fun, pci_vendor_id, pci_device_id, bar)
}
}

94
src/net/os/time.jakt Normal file
View file

@ -0,0 +1,94 @@
import extern c "time.h" {
extern fn time_busy(anon duration: i64)
extern fn time_jiffies() -> i64
extern fn time_now() -> i64
extern fn time_sleep(anon duration: i64)
}
struct Time {
fn busy(anon duration: i64) {
time_busy(duration)
}
fn jiffies() throws -> i64 {
return time_jiffies()
}
fn now() throws -> i64 {
return time_now()
}
fn cdate_to_unix(anon cdate: i64) -> i64 {
// (cdate - Str2Date("1/1/1970") / CDATE_FREQ + NIST_TIME_OFFSET
return (cdate - 3090344933588992) / 49710 + 8575
}
fn unix_to_cdate(anon unix: i64) -> i64 {
// (unix - NIST_TIME_OFFSET) * CDATE_FREQ + Str2Date("1/1/1970")
return (unix - 8575) * 49710 + 3090344933588992
}
fn sleep(anon duration: i64) {
time_sleep(duration)
}
fn timestamp_from_unix(anon timestamp: i64) -> String {
let SECS_PER_DAY = 86400
let DAYS_PER_YEAR = 365
let DAYS_PER_LYEAR = 366
let DAYS_PER_LYEAR_PERIOD = 146097
let YEARS_PER_LYEAR_PERIOD = 400
mut days = timestamp / SECS_PER_DAY
mut remainder = timestamp - (days * SECS_PER_DAY)
if timestamp < 0 and remainder == 0 {
days++
remainder -= SECS_PER_DAY
}
mut cur_year = 0
mut months: [i64] = []
mut tmp_days = 0
let month_tab = [ 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334 ]
let month_tab_leap = [ -1, 30, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334 ]
tmp_days = days;
if tmp_days >= DAYS_PER_LYEAR_PERIOD or tmp_days <= -DAYS_PER_LYEAR_PERIOD {
cur_year += YEARS_PER_LYEAR_PERIOD * (tmp_days / DAYS_PER_LYEAR_PERIOD);
tmp_days -= DAYS_PER_LYEAR_PERIOD * (tmp_days / DAYS_PER_LYEAR_PERIOD);
}
while tmp_days >= DAYS_PER_LYEAR {
cur_year++;
if cur_year % 4 == 0 {
tmp_days -= DAYS_PER_LYEAR;
} else {
tmp_days -= DAYS_PER_YEAR;
}
}
if cur_year % 4 == 0 {
months = month_tab_leap
} else {
months = month_tab
}
mut i = 11
while i > 0 {
if tmp_days > months[i] {
break;
}
i--
}
let year = 1970 + cur_year
let month = i + 1
let day = tmp_days - months[i]
let hours = remainder / 3600
let minutes = (remainder - hours * 3600) / 60
let seconds = remainder % 60
mut sb = StringBuilder::create()
sb.clear()
sb.appendff("{:0>4d}-{:0>2d}-{:0>2d}T{:0>2d}:{:0>2d}:{:0>2d}.000Z", year, month, day, hours, minutes, seconds)
return sb.to_string()
}
fn timestamp_from_cdate(anon cdate: i64) -> String {
return timestamp_from_unix(cdate_to_unix(cdate))
}
}

1675
src/net/tcpip.jakt Normal file

File diff suppressed because it is too large Load diff

60
src/tlse/LICENSE vendored Normal file
View file

@ -0,0 +1,60 @@
This software is available under your choice of one of the following licenses.
Choose whichever you prefer.
===============================================================================
License Choice 1 - The 2-Clause BSD License
===============================================================================
Copyright (c) 2016 - 2024, Eduard Suica
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
===============================================================================
License Choice 2 - Public Domain (Unlicense)
===============================================================================
This is free and unencumbered software released into the public domain.
Anyone is free to copy, modify, publish, use, compile, sell, or
distribute this software, either in source code form or as a compiled
binary, for any purpose, commercial or non-commercial, and by any
means.
In jurisdictions that recognize copyright laws, the author or authors
of this software dedicate any and all copyright interest in the
software to the public domain. We make this dedication for the benefit
of the public at large and to the detriment of our heirs and
successors. We intend this dedication to be an overt act of
relinquishment in perpetuity of all present and future rights to this
software under copyright law.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
OTHER DEALINGS IN THE SOFTWARE.
For more information, please refer to <http://unlicense.org/>

34766
src/tlse/libtomcrypt.c vendored Normal file

File diff suppressed because it is too large Load diff

12374
src/tlse/tlse.c vendored Normal file

File diff suppressed because it is too large Load diff

472
src/tlse/tlse.h vendored Normal file
View file

@ -0,0 +1,472 @@
#ifndef TLSE_H
#define TLSE_H
// #define DEBUG
// define TLS_LEGACY_SUPPORT to support TLS 1.1/1.0 (legacy)
// legacy support it will use an additional 272 bytes / context
#ifndef NO_TLS_LEGACY_SUPPORT
#define TLS_LEGACY_SUPPORT
#endif
// SSL_* style blocking APIs
#ifndef NO_SSL_COMPATIBLE_INTERFACE
#define SSL_COMPATIBLE_INTERFACE
#endif
// support ChaCha20/Poly1305
#if !defined(__BIG_ENDIAN__) && ((!defined(__BYTE_ORDER)) || (__BYTE_ORDER == __LITTLE_ENDIAN))
// not working on big endian machines
#ifndef NO_TLS_WITH_CHACHA20_POLY1305
#define TLS_WITH_CHACHA20_POLY1305
#endif
#endif
#ifndef NO_TLS_13
#define WITH_TLS_13
#endif
// support forward secrecy (Diffie-Hellman ephemeral)
#ifndef NO_TLS_FORWARD_SECRECY
#define TLS_FORWARD_SECRECY
#endif
// support client-side ECDHE
#ifndef NO_TLS_CLIENT_ECDHE
#define TLS_CLIENT_ECDHE
#endif
// suport ecdsa
#ifndef NO_TLS_ECDSA_SUPPORTED
#define TLS_ECDSA_SUPPORTED
#endif
// suport ecdsa client-side
#define TLS_CLIENT_ECDSA
// TLS renegotiation is disabled by default (secured or not)
// do not uncomment next line!
// #define TLS_ACCEPT_SECURE_RENEGOTIATION
// basic superficial X509v1 certificate support
#ifndef NO_TLS_X509_V1_SUPPORT
#define TLS_X509_V1_SUPPORT
#endif
// disable TLS_RSA_WITH_* ciphers
#ifndef NO_TLS_ROBOT_MITIGATION
#define TLS_ROBOT_MITIGATION
#endif
#define SSL_V30 0x0300
#define TLS_V10 0x0301
#define TLS_V11 0x0302
#define TLS_V12 0x0303
#define TLS_V13 0x0304
#define DTLS_V10 0xFEFF
#define DTLS_V12 0xFEFD
#define DTLS_V13 0xFEFC
#define TLS_NEED_MORE_DATA 0
#define TLS_GENERIC_ERROR -1
#define TLS_BROKEN_PACKET -2
#define TLS_NOT_UNDERSTOOD -3
#define TLS_NOT_SAFE -4
#define TLS_NO_COMMON_CIPHER -5
#define TLS_UNEXPECTED_MESSAGE -6
#define TLS_CLOSE_CONNECTION -7
#define TLS_COMPRESSION_NOT_SUPPORTED -8
#define TLS_NO_MEMORY -9
#define TLS_NOT_VERIFIED -10
#define TLS_INTEGRITY_FAILED -11
#define TLS_ERROR_ALERT -12
#define TLS_BROKEN_CONNECTION -13
#define TLS_BAD_CERTIFICATE -14
#define TLS_UNSUPPORTED_CERTIFICATE -15
#define TLS_NO_RENEGOTIATION -16
#define TLS_FEATURE_NOT_SUPPORTED -17
#define TLS_DECRYPTION_FAILED -20
#define TLS_AES_128_GCM_SHA256 0x1301
#define TLS_AES_256_GCM_SHA384 0x1302
#define TLS_CHACHA20_POLY1305_SHA256 0x1303
#define TLS_AES_128_CCM_SHA256 0x1304
#define TLS_AES_128_CCM_8_SHA256 0x1305
#define TLS_RSA_WITH_AES_128_CBC_SHA 0x002F
#define TLS_RSA_WITH_AES_256_CBC_SHA 0x0035
#define TLS_RSA_WITH_AES_128_CBC_SHA256 0x003C
#define TLS_RSA_WITH_AES_256_CBC_SHA256 0x003D
#define TLS_RSA_WITH_AES_128_GCM_SHA256 0x009C
#define TLS_RSA_WITH_AES_256_GCM_SHA384 0x009D
// forward secrecy
#define TLS_DHE_RSA_WITH_AES_128_CBC_SHA 0x0033
#define TLS_DHE_RSA_WITH_AES_256_CBC_SHA 0x0039
#define TLS_DHE_RSA_WITH_AES_128_CBC_SHA256 0x0067
#define TLS_DHE_RSA_WITH_AES_256_CBC_SHA256 0x006B
#define TLS_DHE_RSA_WITH_AES_128_GCM_SHA256 0x009E
#define TLS_DHE_RSA_WITH_AES_256_GCM_SHA384 0x009F
#define TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA 0xC013
#define TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA 0xC014
#define TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256 0xC027
#define TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 0xC02F
#define TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 0xC030
#define TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA 0xC009
#define TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA 0xC00A
#define TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256 0xC023
#define TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384 0xC024
#define TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256 0xC02B
#define TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384 0xC02C
#define TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256 0xCCA8
#define TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256 0xCCA9
#define TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256 0xCCAA
#define TLS_FALLBACK_SCSV 0x5600
#define TLS_UNSUPPORTED_ALGORITHM 0x00
#define TLS_RSA_SIGN_RSA 0x01
#define TLS_RSA_SIGN_MD5 0x04
#define TLS_RSA_SIGN_SHA1 0x05
#define TLS_RSA_SIGN_SHA256 0x0B
#define TLS_RSA_SIGN_SHA384 0x0C
#define TLS_RSA_SIGN_SHA512 0x0D
#define TLS_ECDSA_SIGN_SHA256 0x0E
#define TLS_EC_PUBLIC_KEY 0x11
#define TLS_EC_prime192v1 0x12
#define TLS_EC_prime192v2 0x13
#define TLS_EC_prime192v3 0x14
#define TLS_EC_prime239v1 0x15
#define TLS_EC_prime239v2 0x16
#define TLS_EC_prime239v3 0x17
#define TLS_EC_prime256v1 0x18
#define TLS_EC_secp224r1 21
#define TLS_EC_secp256r1 23
#define TLS_EC_secp384r1 24
#define TLS_EC_secp521r1 25
#define TLS_ALERT_WARNING 0x01
#define TLS_ALERT_CRITICAL 0x02
#ifdef TLS_ROBOT_MITIGATION
#define TLS_CIPHERS_SIZE(n, mitigated) n * 2
#else
#define TLS_CIPHERS_SIZE(n, mitigated) (n + mitigated) * 2
#endif
#define SRTP_AES128_CM_HMAC_SHA1_80 0x0001
#define SRTP_AES128_CM_HMAC_SHA1_32 0x0002
#define SRTP_NULL_HMAC_SHA1_80 0x0005
#define SRTP_NULL_HMAC_SHA1_32 0x0006
#define SRTP_AEAD_AES_128_GCM 0x0007
#define SRTP_AEAD_AES_256_GCM 0x0008
#define SRTP_NULL 0
#define SRTP_AES_CM 1
#define SRTP_AUTH_NULL 0
#define SRTP_AUTH_HMAC_SHA1 1
#ifdef __cplusplus
extern "C" {
#endif
typedef enum {
close_notify = 0,
unexpected_message = 10,
bad_record_mac = 20,
decryption_failed_RESERVED = 21,
record_overflow = 22,
decompression_failure = 30,
handshake_failure = 40,
no_certificate_RESERVED = 41,
bad_certificate = 42,
unsupported_certificate = 43,
certificate_revoked = 44,
certificate_expired = 45,
certificate_unknown = 46,
illegal_parameter = 47,
unknown_ca = 48,
access_denied = 49,
decode_error = 50,
decrypt_error = 51,
export_restriction_RESERVED = 60,
protocol_version = 70,
insufficient_security = 71,
internal_error = 80,
inappropriate_fallback = 86,
user_canceled = 90,
no_renegotiation = 100,
unsupported_extension = 110,
no_error = 255
} TLSAlertDescription;
// forward declarations
struct TLSPacket;
struct TLSCertificate;
struct TLSContext;
struct ECCCurveParameters;
typedef struct TLSContext TLS;
typedef struct TLSCertificate Certificate;
// webrtc datachannel
struct TLSRTCPeerConnection;
typedef int (*tls_validation_function)(struct TLSContext *context, struct TLSCertificate **certificate_chain, int len);
/*
Global initialization. Optional, as it will be called automatically;
however, the initialization is not thread-safe, so if you intend to use TLSe
from multiple threads, you'll need to call tls_init() once, from a single thread,
before using the library.
*/
void tls_init();
unsigned char *tls_pem_decode(const unsigned char *data_in, unsigned int input_length, int cert_index, unsigned int *output_len);
struct TLSCertificate *tls_create_certificate();
int tls_certificate_valid_subject(struct TLSCertificate *cert, const char *subject);
int tls_certificate_valid_subject_name(const unsigned char *cert_subject, const char *subject);
int tls_certificate_is_valid(struct TLSCertificate *cert);
void tls_certificate_set_copy(unsigned char **member, const unsigned char *val, int len);
void tls_certificate_set_copy_date(unsigned char **member, const unsigned char *val, int len);
void tls_certificate_set_key(struct TLSCertificate *cert, const unsigned char *val, int len);
void tls_certificate_set_priv(struct TLSCertificate *cert, const unsigned char *val, int len);
void tls_certificate_set_sign_key(struct TLSCertificate *cert, const unsigned char *val, int len);
char *tls_certificate_to_string(struct TLSCertificate *cert, char *buffer, int len);
void tls_certificate_set_exponent(struct TLSCertificate *cert, const unsigned char *val, int len);
void tls_certificate_set_serial(struct TLSCertificate *cert, const unsigned char *val, int len);
void tls_certificate_set_algorithm(struct TLSContext *context, unsigned int *algorithm, const unsigned char *val, int len);
void tls_destroy_certificate(struct TLSCertificate *cert);
struct TLSPacket *tls_create_packet(struct TLSContext *context, unsigned char type, unsigned short version, int payload_size_hint);
void tls_destroy_packet(struct TLSPacket *packet);
void tls_packet_update(struct TLSPacket *packet);
int tls_packet_append(struct TLSPacket *packet, const unsigned char *buf, unsigned int len);
int tls_packet_uint8(struct TLSPacket *packet, unsigned char i);
int tls_packet_uint16(struct TLSPacket *packet, unsigned short i);
int tls_packet_uint32(struct TLSPacket *packet, unsigned int i);
int tls_packet_uint24(struct TLSPacket *packet, unsigned int i);
int tls_random(unsigned char *key, int len);
/*
Get encrypted data to write, if any. Once you've sent all of it, call
tls_buffer_clear().
*/
const unsigned char *tls_get_write_buffer(struct TLSContext *context, unsigned int *outlen);
void tls_buffer_clear(struct TLSContext *context);
/* Returns 1 for established, 0 for not established yet, and -1 for a critical error. */
int tls_established(struct TLSContext *context);
/* Discards any unread decrypted data not consumed by tls_read(). */
void tls_read_clear(struct TLSContext *context);
/*
Reads any unread decrypted data (see tls_consume_stream). If you don't read all of it,
the remainder will be left in the internal buffers for next tls_read(). Returns -1 for
fatal error, 0 for no more data, or otherwise the number of bytes copied into the buffer
(up to a maximum of the given size).
*/
int tls_read(struct TLSContext *context, unsigned char *buf, unsigned int size);
struct TLSContext *tls_create_context(unsigned char is_server, unsigned short version);
const struct ECCCurveParameters *tls_set_curve(struct TLSContext *context, const struct ECCCurveParameters *curve);
/* Create a context for a given client, from a server context. Returns NULL on error. */
struct TLSContext *tls_accept(struct TLSContext *context);
int tls_set_default_dhe_pg(struct TLSContext *context, const char *p_hex_str, const char *g_hex_str);
void tls_destroy_context(struct TLSContext *context);
int tls_cipher_supported(struct TLSContext *context, unsigned short cipher);
int tls_cipher_is_fs(struct TLSContext *context, unsigned short cipher);
int tls_choose_cipher(struct TLSContext *context, const unsigned char *buf, int buf_len, int *scsv_set);
int tls_cipher_is_ephemeral(struct TLSContext *context);
const char *tls_cipher_name(struct TLSContext *context);
int tls_is_ecdsa(struct TLSContext *context);
struct TLSPacket *tls_build_client_key_exchange(struct TLSContext *context);
struct TLSPacket *tls_build_server_key_exchange(struct TLSContext *context, int method);
struct TLSPacket *tls_build_hello(struct TLSContext *context, int tls13_downgrade);
struct TLSPacket *tls_certificate_request(struct TLSContext *context);
struct TLSPacket *tls_build_verify_request(struct TLSContext *context);
int tls_parse_hello(struct TLSContext *context, const unsigned char *buf, int buf_len, unsigned int *write_packets, unsigned int *dtls_verified);
int tls_parse_certificate(struct TLSContext *context, const unsigned char *buf, int buf_len, int is_client);
int tls_parse_server_key_exchange(struct TLSContext *context, const unsigned char *buf, int buf_len);
int tls_parse_client_key_exchange(struct TLSContext *context, const unsigned char *buf, int buf_len);
int tls_parse_server_hello_done(struct TLSContext *context, const unsigned char *buf, int buf_len);
int tls_parse_finished(struct TLSContext *context, const unsigned char *buf, int buf_len, unsigned int *write_packets);
int tls_parse_verify(struct TLSContext *context, const unsigned char *buf, int buf_len);
int tls_parse_payload(struct TLSContext *context, const unsigned char *buf, int buf_len, tls_validation_function certificate_verify);
int tls_parse_message(struct TLSContext *context, unsigned char *buf, int buf_len, tls_validation_function certificate_verify);
int tls_certificate_verify_signature(struct TLSCertificate *cert, struct TLSCertificate *parent);
int tls_certificate_chain_is_valid(struct TLSCertificate **certificates, int len);
int tls_certificate_chain_is_valid_root(struct TLSContext *context, struct TLSCertificate **certificates, int len);
/*
Add a certificate or a certificate chain to the given context, in PEM form.
Returns a negative value (TLS_GENERIC_ERROR etc.) on error, 0 if there were no
certificates in the buffer, or the number of loaded certificates on success.
*/
int tls_load_certificates(struct TLSContext *context, const unsigned char *pem_buffer, int pem_size);
/*
Add a private key to the given context, in PEM form. Returns a negative value
(TLS_GENERIC_ERROR etc.) on error, 0 if there was no private key in the
buffer, or 1 on success.
*/
int tls_load_private_key(struct TLSContext *context, const unsigned char *pem_buffer, int pem_size);
struct TLSPacket *tls_build_certificate(struct TLSContext *context);
struct TLSPacket *tls_build_finished(struct TLSContext *context);
struct TLSPacket *tls_build_change_cipher_spec(struct TLSContext *context);
struct TLSPacket *tls_build_done(struct TLSContext *context);
struct TLSPacket *tls_build_message(struct TLSContext *context, const unsigned char *data, unsigned int len);
int tls_client_connect(struct TLSContext *context);
int tls_write(struct TLSContext *context, const unsigned char *data, unsigned int len);
struct TLSPacket *tls_build_alert(struct TLSContext *context, char critical, unsigned char code);
int tls_connection_status(struct TLSContext *context);
/*
Process a given number of input bytes from a socket. If the other side just
presented a certificate and certificate_verify is not NULL, it will be called.
Returns 0 if there's no data ready yet, a negative value (see
TLS_GENERIC_ERROR etc.) for an error, or a positive value (the number of bytes
used from buf) if one or more complete TLS messages were received. The data
is copied into an internal buffer even if not all of it was consumed,
so you should not re-send it the next time.
Decrypted data, if any, should be read back with tls_read(). Can change the
status of tls_established(). If the library has anything to send back on the
socket (e.g. as part of the handshake), tls_get_write_buffer() will return
non-NULL.
*/
int tls_consume_stream(struct TLSContext *context, const unsigned char *buf, int buf_len, tls_validation_function certificate_verify);
void tls_close_notify(struct TLSContext *context);
void tls_alert(struct TLSContext *context, unsigned char critical, int code);
/* Whether tls_consume_stream() has data in its buffer that is not processed yet. */
int tls_pending(struct TLSContext *context);
/*
Set the context as serializable or not. Must be called before negotiation.
Exportable contexts use a bit more memory, to be able to hold the keys.
Note that imported keys are not reexportable unless TLS_REEXPORTABLE is set.
*/
void tls_make_exportable(struct TLSContext *context, unsigned char exportable_flag);
int tls_export_context(struct TLSContext *context, unsigned char *buffer, unsigned int buf_len, unsigned char small_version);
struct TLSContext *tls_import_context(const unsigned char *buffer, unsigned int buf_len);
int tls_is_broken(struct TLSContext *context);
int tls_request_client_certificate(struct TLSContext *context);
int tls_client_verified(struct TLSContext *context);
const char *tls_sni(struct TLSContext *context);
int tls_sni_set(struct TLSContext *context, const char *sni);
int tls_sni_nset(struct TLSContext *context, const char *sni, unsigned int len);
// set DTLS-SRTP mode for DTLS context
int tls_srtp_set(struct TLSContext *context);
int tls_srtp_key(struct TLSContext *context, unsigned char *buffer);
int tls_stun_parse(unsigned char *msg, int len, char *pwd, int pwd_len, unsigned char is_ipv6, unsigned char *addr, unsigned int port, unsigned char *response_buffer);
int tls_stun_build(unsigned char transaction_id[12], char *username, int username_len, char *pwd, int pwd_len, unsigned char *msg);
int tls_is_stun(const unsigned char *msg, int len);
typedef int (*tls_peerconnection_write_function)(struct TLSRTCPeerConnection *channel, const unsigned char *msg, int msg_len);
struct TLSRTCPeerConnection *tls_peerconnection_context(unsigned char active, tls_validation_function certificate_verify, void *userdata);
struct TLSRTCPeerConnection *tls_peerconnection_duplicate(struct TLSRTCPeerConnection *channel, void *userdata);
struct TLSContext *tls_peerconnection_dtls_context(struct TLSRTCPeerConnection *channel);
int tls_peerconnection_remote_credentials(struct TLSRTCPeerConnection *channel, char *remote_username, int remote_username_len, char *remote_pwd, int remote_pwd_len, char *remote_fingerprint, int remote_fingerprint_len);
const char *tls_peerconnection_local_pwd(struct TLSRTCPeerConnection *channel);
const char *tls_peerconnection_local_username(struct TLSRTCPeerConnection *channel);
void *tls_peerconnection_userdata(struct TLSRTCPeerConnection *channel);
int tls_peerconnection_load_keys(struct TLSRTCPeerConnection *channel, const unsigned char *pem_pub_key, int pem_pub_key_size, const unsigned char *pem_priv_key, int pem_priv_key_size);
int tls_peerconnection_connect(struct TLSRTCPeerConnection *channel, tls_peerconnection_write_function write_function);
int tls_peerconnection_iterate(struct TLSRTCPeerConnection *channel, unsigned char *buf, int buf_len, unsigned char *addr, int port, unsigned char is_ipv6, tls_peerconnection_write_function write_function, int *validate_addr);
int tls_peerconnection_get_write_msg(struct TLSRTCPeerConnection *channel, unsigned char *buf);
int tls_peerconnection_get_read_msg(struct TLSRTCPeerConnection *channel, unsigned char *buf);
int tls_peerconnection_status(struct TLSRTCPeerConnection *channel);
void tls_destroy_peerconnection(struct TLSRTCPeerConnection *channel);
int tls_cert_fingerprint(const char *pem_data, int len, char *buffer, unsigned int buf_len);
int tls_load_root_certificates(struct TLSContext *context, const unsigned char *pem_buffer, int pem_size);
int tls_default_verify(struct TLSContext *context, struct TLSCertificate **certificate_chain, int len);
void tls_print_certificate(const char *fname);
int tls_add_alpn(struct TLSContext *context, const char *alpn);
int tls_alpn_contains(struct TLSContext *context, const char *alpn, unsigned char alpn_size);
const char *tls_alpn(struct TLSContext *context);
// useful when renewing certificates for servers, without the need to restart the server
int tls_clear_certificates(struct TLSContext *context);
int tls_make_ktls(struct TLSContext *context, int socket);
int tls_unmake_ktls(struct TLSContext *context, int socket);
/*
Creates a new DTLS random cookie secret to be used in HelloVerifyRequest (server-side).
It is recommended to call this function from time to time, to protect against some
DoS attacks.
*/
void dtls_reset_cookie_secret();
int tls_remote_error(struct TLSContext *context);
#ifdef SSL_COMPATIBLE_INTERFACE
#define SSL_SERVER_RSA_CERT 1
#define SSL_SERVER_RSA_KEY 2
typedef struct TLSContext SSL_CTX;
typedef struct TLSContext SSL;
#define SSL_FILETYPE_PEM 1
#define SSL_VERIFY_NONE 0
#define SSL_VERIFY_PEER 1
#define SSL_VERIFY_FAIL_IF_NO_PEER_CERT 2
#define SSL_VERIFY_CLIENT_ONCE 3
typedef struct {
int fd;
tls_validation_function certificate_verify;
void *recv;
void *send;
void *user_data;
} SSLUserData;
int SSL_library_init();
void SSL_load_error_strings();
void OpenSSL_add_all_algorithms();
void OpenSSL_add_all_ciphers();
void OpenSSL_add_all_digests();
void EVP_cleanup();
int SSLv3_server_method();
int SSLv3_client_method();
struct TLSContext *SSL_new(struct TLSContext *context);
int SSL_CTX_use_certificate_file(struct TLSContext *context, const char *filename, int dummy);
int SSL_CTX_use_PrivateKey_file(struct TLSContext *context, const char *filename, int dummy);
int SSL_CTX_check_private_key(struct TLSContext *context);
struct TLSContext *SSL_CTX_new(int method);
void SSL_free(struct TLSContext *context);
void SSL_CTX_free(struct TLSContext *context);
int SSL_get_error(struct TLSContext *context, int ret);
int SSL_set_fd(struct TLSContext *context, int socket);
void *SSL_set_userdata(struct TLSContext *context, void *data);
void *SSL_userdata(struct TLSContext *context);
int SSL_CTX_root_ca(struct TLSContext *context, const char *pem_filename);
void SSL_CTX_set_verify(struct TLSContext *context, int mode, tls_validation_function verify_callback);
int SSL_accept(struct TLSContext *context);
int SSL_connect(struct TLSContext *context);
int SSL_shutdown(struct TLSContext *context);
int SSL_write(struct TLSContext *context, const void *buf, unsigned int len);
int SSL_read(struct TLSContext *context, void *buf, unsigned int len);
int SSL_pending(struct TLSContext *context);
int SSL_set_io(struct TLSContext *context, void *recv, void *send);
#endif
#ifdef TLS_SRTP
struct SRTPContext;
struct SRTPContext *srtp_init(unsigned char mode, unsigned char auth_mode);
int srtp_key(struct SRTPContext *context, const void *key, int keylen, const void *salt, int saltlen, int tag_bits);
int srtp_inline(struct SRTPContext *context, const char *b64, int tag_bits);
int srtp_encrypt(struct SRTPContext *context, unsigned char rtcp, const unsigned char *pt_header, int pt_len, const unsigned char *payload, unsigned int payload_len, unsigned char *out, int *out_buffer_len);
int srtp_decrypt(struct SRTPContext *context, unsigned char rtcp, const unsigned char *pt_header, int pt_len, const unsigned char *payload, unsigned int payload_len, unsigned char *out, int *out_buffer_len);
void srtp_destroy(struct SRTPContext *context);
struct SRTPContext *tls_peerconnection_srtp_local(struct TLSRTCPeerConnection *channel);
struct SRTPContext *tls_peerconnection_srtp_remote(struct TLSRTCPeerConnection *channel);
int tls_peerconnection_encrypt(struct TLSRTCPeerConnection *channel, unsigned char rtcp, const unsigned char *pt_header, int pt_len, const unsigned char *payload, unsigned int payload_len, unsigned char *out, int *out_buffer_len);
int tls_peerconnection_decrypt(struct TLSRTCPeerConnection *channel, unsigned char rtcp, const unsigned char *pt_header, int pt_len, const unsigned char *payload, unsigned int payload_len, unsigned char *out, int *out_buffer_len);
#endif
#ifdef __cplusplus
} // extern "C"
#endif
#endif