Add BufferManager and fix all memory leaks.
This commit is contained in:
parent
cb88f3c3b3
commit
82e3e8491c
37
src/BufferManager.zig
Normal file
37
src/BufferManager.zig
Normal file
|
@ -0,0 +1,37 @@
|
|||
const std = @import("std");
|
||||
const BufferInfo = @import("./qtshit/types/UserType.zig").BufferInfo;
|
||||
|
||||
pub const BufferManager = struct {
|
||||
allocator: *std.mem.Allocator,
|
||||
buffers: std.ArrayList(BufferInfo),
|
||||
|
||||
pub fn addBufferInfo(s: *BufferManager, bufferInfo: BufferInfo) !void {
|
||||
try s.buffers.append(BufferInfo{
|
||||
.ID = bufferInfo.ID,
|
||||
.NetworkID = bufferInfo.NetworkID,
|
||||
.Type = bufferInfo.Type,
|
||||
.Name = try s.allocator.dupe(u8, bufferInfo.Name),
|
||||
});
|
||||
}
|
||||
pub fn getFirstByName(s: *BufferManager, name: []const u8) !?BufferInfo {
|
||||
for (s.buffers.items) |item| {
|
||||
if (std.mem.eql(u8, item.Name, name)) {
|
||||
return item;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
pub fn deinit(s: *BufferManager, ) void {
|
||||
for (s.buffers.items) |item| {
|
||||
s.allocator.free(item.Name);
|
||||
}
|
||||
s.buffers.deinit();
|
||||
}
|
||||
};
|
||||
|
||||
pub fn initBufferManager(allocator: *std.mem.Allocator) BufferManager {
|
||||
return BufferManager{
|
||||
.allocator = allocator,
|
||||
.buffers = std.ArrayList(BufferInfo).init(allocator),
|
||||
};
|
||||
}
|
|
@ -1,4 +1,7 @@
|
|||
const std = @import("std");
|
||||
|
||||
const BufferManager = @import("./BufferManager.zig");
|
||||
|
||||
const read = @import("./qtshit/read.zig");
|
||||
const write = @import("./qtshit/write.zig");
|
||||
const range = @import("./qtshit/utils/RangeIter.zig").range;
|
||||
|
@ -6,6 +9,8 @@ const QVariantType = @import("./qtshit/types/QVariant.zig").QVariant;
|
|||
const prettyPrintQVariant = @import("./qtshit/utils/prettyPrintQVariant.zig").prettyPrintQVariant;
|
||||
const freeQVariant = @import("./qtshit/utils/free/freeQVariant.zig").freeQVariant;
|
||||
const QVariantMapToQVariantList = @import("./qtshit/utils/QVariantMapToQVariantList.zig").QVariantMapToQVariantList;
|
||||
const UserType = @import("./qtshit/types/UserType.zig");
|
||||
|
||||
const tls = @import("./deps/iguanaTLS/src/main.zig");
|
||||
|
||||
fn dumpDebug(name: []const u8, list: std.ArrayList(u8)) !void {
|
||||
|
@ -23,6 +28,7 @@ fn dumpDebug(name: []const u8, list: std.ArrayList(u8)) !void {
|
|||
pub const Client = struct {
|
||||
allocator: *std.mem.Allocator,
|
||||
stream: *std.net.Stream,
|
||||
bufferManager: BufferManager.BufferManager,
|
||||
|
||||
pub var tlsAllowed = !true;
|
||||
pub var tlsConnected = !true;
|
||||
|
@ -30,6 +36,11 @@ pub const Client = struct {
|
|||
pub const TLSStream = tls.Client(std.net.Stream.Reader, std.net.Stream.Writer, tls.ciphersuites.all, false);
|
||||
pub var tlsClient: TLSStream = undefined;
|
||||
|
||||
pub fn deinit(s: *Client) void {
|
||||
s.bufferManager.deinit();
|
||||
}
|
||||
|
||||
|
||||
pub fn initTLS(s: *Client) !void {
|
||||
if (!tlsConnected and tlsAllowed) {
|
||||
var randBuf: [32]u8 = undefined;
|
||||
|
@ -84,6 +95,7 @@ pub const Client = struct {
|
|||
pub fn readFrame(s: *Client) !QVariantType {
|
||||
try s.initTLS();
|
||||
var data: std.ArrayList(u8) = undefined;
|
||||
defer data.deinit();
|
||||
|
||||
if (tlsConnected) {
|
||||
var reader = tlsClient.reader();
|
||||
|
@ -112,18 +124,22 @@ pub const Client = struct {
|
|||
}
|
||||
pub fn quassel_init_packet(s: *Client) !void {
|
||||
var data = std.ArrayList(u8).init(s.allocator);
|
||||
defer data.deinit();
|
||||
|
||||
var map = std.StringHashMap(QVariantType).init(s.allocator);
|
||||
defer map.deinit();
|
||||
|
||||
try map.put("MsgType", .{ .String = "ClientInit" });
|
||||
try map.put("UseCompression", .{ .UInt = 0 });
|
||||
try map.put("UseSsl", .{ .UInt = 1 });
|
||||
|
||||
try map.put("ProtocolVersion", .{ .UInt = 10 });
|
||||
try map.put("ClientVersion", .{ .String = "0.1 (quasselclient)" });
|
||||
try map.put("ClientDate", .{ .String = "Wed, 02 Jun 2021 17:30:30 +0100" });
|
||||
try map.put("Features", .{ .Int = 0x00008000 });
|
||||
|
||||
var featureList = std.ArrayList([]const u8).init(s.allocator);
|
||||
defer featureList.deinit();
|
||||
|
||||
try featureList.append("LongTime");
|
||||
try featureList.append("LongMessageID");
|
||||
try featureList.append("SenderPrefixes");
|
||||
|
@ -137,16 +153,18 @@ pub const Client = struct {
|
|||
|
||||
try s.writeFrame(data);
|
||||
|
||||
var varient = try s.readFrame();
|
||||
prettyPrintQVariant(varient, 0);
|
||||
tlsAllowed = varient.QVariantMap.get("SupportSsl").?.Byte == 1;
|
||||
freeQVariant(varient, s.allocator);
|
||||
var variant = try s.readFrame();
|
||||
defer freeQVariant(variant, s.allocator);
|
||||
tlsAllowed = variant.QVariantMap.get("SupportSsl").?.Byte == 1;
|
||||
}
|
||||
|
||||
pub fn quassel_login(s: *Client, username: []const u8, password: []const u8) !void {
|
||||
var data = std.ArrayList(u8).init(s.allocator);
|
||||
defer data.deinit();
|
||||
|
||||
var map = std.StringHashMap(QVariantType).init(s.allocator);
|
||||
defer map.deinit();
|
||||
|
||||
try map.put("MsgType", .{ .String = "ClientLogin" });
|
||||
try map.put("User", .{ .String = username });
|
||||
try map.put("Password", .{ .String = password });
|
||||
|
@ -156,13 +174,61 @@ pub const Client = struct {
|
|||
});
|
||||
|
||||
try s.writeFrame(data);
|
||||
|
||||
var loginResponse = try s.readFrame();
|
||||
defer freeQVariant(loginResponse, s.allocator);
|
||||
|
||||
var loginResponseMap = loginResponse.QVariantMap;
|
||||
if (loginResponseMap.get("MsgType")) |msgType| {
|
||||
if (std.mem.eql(u8, msgType.String, "ClientLoginReject")) {
|
||||
return error.InvalidLogin;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn handle_session_init_packet(s: *Client, sessionState: std.StringHashMap(QVariantType)) !void {
|
||||
for (sessionState.get("BufferInfos").?.QVariantList) |qvar| {
|
||||
try s.bufferManager.addBufferInfo(qvar.UserType.BufferInfo);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn read_quassel_packet(s: *Client) !void {
|
||||
std.debug.print("\n\nQuassel Packet: \n", .{});
|
||||
var varient = try s.readFrame();
|
||||
prettyPrintQVariant(varient, 0);
|
||||
freeQVariant(varient, s.allocator);
|
||||
var variant = try s.readFrame();
|
||||
defer freeQVariant(variant, s.allocator);
|
||||
|
||||
switch (variant) {
|
||||
.QVariantMap => |map| {
|
||||
if (map.get("MsgType")) |msgType| {
|
||||
if (std.mem.eql(u8, msgType.String, "SessionInit")) {
|
||||
var sessionState = map.get("SessionState").?.QVariantMap;
|
||||
try s.handle_session_init_packet(sessionState);
|
||||
}
|
||||
}
|
||||
},
|
||||
else => {
|
||||
std.debug.print("\n\n Unknown: Quassel Packet: \n", .{});
|
||||
prettyPrintQVariant(variant, 0);
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
pub fn send_message(s: *Client, bufferInfo: UserType.BufferInfo, message: []const u8) !void {
|
||||
var data = std.ArrayList(u8).init(s.allocator);
|
||||
defer data.deinit();
|
||||
|
||||
var listItems = std.ArrayList(QVariantType).init(s.allocator);
|
||||
defer listItems.deinit();
|
||||
|
||||
try listItems.append(.{ .Int = 2 });
|
||||
try listItems.append(.{ .QByteArray = "2sendInput(BufferInfo,QString)" });
|
||||
try listItems.append(.{ .UserType = .{ .BufferInfo = bufferInfo } });
|
||||
try listItems.append(.{ .String = message });
|
||||
|
||||
try write.writeQVariant(data.writer(), s.allocator, .{
|
||||
.QVariantList = listItems.items,
|
||||
});
|
||||
|
||||
try s.writeFrame(data);
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -170,5 +236,6 @@ pub fn initClient(allocator: *std.mem.Allocator, stream: *std.net.Stream) Client
|
|||
return Client{
|
||||
.allocator = allocator,
|
||||
.stream = stream,
|
||||
.bufferManager = BufferManager.initBufferManager(allocator),
|
||||
};
|
||||
}
|
||||
|
|
37
src/main.zig
37
src/main.zig
|
@ -1,30 +1,40 @@
|
|||
const std = @import("std");
|
||||
|
||||
const read = @import("./qtshit/read.zig");
|
||||
const DebugAllocator = @import("./debug_allocator.zig");
|
||||
const write = @import("./qtshit/write.zig");
|
||||
|
||||
const initClient = @import("./client.zig").initClient;
|
||||
|
||||
pub fn main() !void {
|
||||
const allocator = std.heap.page_allocator;
|
||||
|
||||
pub fn realMain(allocator: *std.mem.Allocator) !void {
|
||||
var argIter = std.process.args();
|
||||
_ = try argIter.next(allocator).?;
|
||||
|
||||
allocator.free(try argIter.next(allocator).?);
|
||||
|
||||
var host = try argIter.next(allocator).?;
|
||||
defer allocator.free(host);
|
||||
var port = try argIter.next(allocator).?;
|
||||
defer allocator.free(port);
|
||||
var portInt = try std.fmt.parseInt(u16, port, 10);
|
||||
var username = try argIter.next(allocator).?;
|
||||
defer allocator.free(username);
|
||||
var password = try argIter.next(allocator).?;
|
||||
defer allocator.free(password);
|
||||
|
||||
std.debug.print("host={s} port={d}\n", .{ host, portInt });
|
||||
|
||||
while (true) {
|
||||
var sock = try std.net.tcpConnectToHost(allocator, host, portInt);
|
||||
|
||||
var client = initClient(allocator, &sock);
|
||||
defer client.deinit();
|
||||
|
||||
try client.handshake();
|
||||
try client.quassel_init_packet();
|
||||
try client.quassel_login(username, password);
|
||||
|
||||
_ = try client.read_quassel_packet();
|
||||
|
||||
var bufferInfo = try client.bufferManager.getFirstByName("z_is_stimky");
|
||||
try client.send_message(bufferInfo.?, "uwu, owo, uwu");
|
||||
|
||||
while (true) {
|
||||
client.read_quassel_packet() catch |err| {
|
||||
if (err == error.DecodeError) {
|
||||
|
@ -32,11 +42,22 @@ pub fn main() !void {
|
|||
} else if (err == error.EndOfStream) {
|
||||
std.debug.print("EOS.\n", .{});
|
||||
std.time.sleep(1000 * std.time.ns_per_ms);
|
||||
continue;
|
||||
return;
|
||||
} else {
|
||||
return err;
|
||||
}
|
||||
};
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
pub fn main() !void {
|
||||
var gpalloc = std.heap.GeneralPurposeAllocator(.{
|
||||
.stack_trace_frames = 20,
|
||||
}){};
|
||||
defer std.debug.assert(!gpalloc.deinit());
|
||||
|
||||
const alloc = &gpalloc.allocator;
|
||||
|
||||
try realMain(alloc);
|
||||
}
|
||||
|
|
|
@ -12,8 +12,9 @@ const readMessage = @import("./readMessage.zig").readMessage;
|
|||
|
||||
pub fn readUserType(reader: anytype, allocator: *std.mem.Allocator) !UserType {
|
||||
var userTypeName = try readQByteArray(reader, allocator);
|
||||
defer allocator.free(userTypeName);
|
||||
|
||||
userTypeName = userTypeName[0 .. userTypeName.len - 1];
|
||||
//std.debug.print("read: readUserType name={s} \n", .{userTypeName});
|
||||
|
||||
if (std.mem.eql(u8, userTypeName, "BufferId")) {
|
||||
return UserType{
|
||||
|
|
|
@ -7,7 +7,7 @@ pub const QVariant = union(enum) {
|
|||
Short: u16,
|
||||
Byte: u8,
|
||||
String: []const u8,
|
||||
QByteArray: []u8,
|
||||
QByteArray: []const u8,
|
||||
QStringList: [][]const u8,
|
||||
QVariantList: []QVariant,
|
||||
QVariantMap: std.StringHashMap(QVariant),
|
||||
|
|
|
@ -20,7 +20,7 @@ pub const BufferInfo = struct {
|
|||
ID: i32,
|
||||
NetworkID: i32,
|
||||
Type: u16,
|
||||
Name: []u8,
|
||||
Name: []const u8,
|
||||
};
|
||||
|
||||
pub const Message = struct {
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
const std = @import("std");
|
||||
|
||||
pub fn freeQByteArray(qbytearray: []u8, allocator: *std.mem.Allocator) void {
|
||||
pub fn freeQByteArray(qbytearray: []const u8, allocator: *std.mem.Allocator) void {
|
||||
allocator.free(qbytearray);
|
||||
}
|
||||
|
|
|
@ -43,22 +43,27 @@ pub fn prettyPrintUserType(usertype: UserType, indentLevel: u64) void {
|
|||
},
|
||||
.IrcUser => |value| {
|
||||
std.debug.print("IrcUser:\n", .{});
|
||||
print_indent_level(indentLevel + 1);
|
||||
prettyPrintQVariantMap(value, indentLevel + 1);
|
||||
},
|
||||
.IrcChannel => |value| {
|
||||
std.debug.print("IrcChannel:\n", .{});
|
||||
print_indent_level(indentLevel + 1);
|
||||
prettyPrintQVariantMap(value, indentLevel + 1);
|
||||
},
|
||||
.Identity => |value| {
|
||||
std.debug.print("Identity:\n", .{});
|
||||
print_indent_level(indentLevel + 1);
|
||||
prettyPrintQVariantMap(value, indentLevel + 1);
|
||||
},
|
||||
.NetworkInfo => |value| {
|
||||
std.debug.print("NetworkInfo:\n", .{});
|
||||
print_indent_level(indentLevel + 1);
|
||||
prettyPrintQVariantMap(value, indentLevel + 1);
|
||||
},
|
||||
.NetworkServer => |value| {
|
||||
std.debug.print("NetworkServer:\n", .{});
|
||||
print_indent_level(indentLevel + 1);
|
||||
prettyPrintQVariantMap(value, indentLevel + 1);
|
||||
},
|
||||
.BufferInfo => |value| {
|
||||
|
@ -106,7 +111,6 @@ pub fn prettyPrintUserType(usertype: UserType, indentLevel: u64) void {
|
|||
}
|
||||
|
||||
pub fn prettyPrintQVariantMap(qvariantmap: std.StringHashMap(QVariant), indentLevel: u64) void {
|
||||
print_indent_level(indentLevel);
|
||||
std.debug.print("QVariantMap:\n", .{});
|
||||
var qMapIter = qvariantmap.iterator();
|
||||
while (qMapIter.next()) |v| {
|
||||
|
|
|
@ -26,7 +26,7 @@ pub fn utf16BEToUtf8(allocator: *std.mem.Allocator, utf16: []u16) ![]u8 {
|
|||
// Big Endian to Little Endian
|
||||
var utf16LE = byteSwapArray(u16, &utf16BE);
|
||||
|
||||
var utf8 = try std.unicode.utf16leToUtf8AllocZ(allocator, utf16LE);
|
||||
var utf8 = try std.unicode.utf16leToUtf8Alloc(allocator, utf16LE);
|
||||
return utf8;
|
||||
}
|
||||
|
||||
|
|
19
src/qtshit/write/usertypes/writeBufferInfo.zig
Normal file
19
src/qtshit/write/usertypes/writeBufferInfo.zig
Normal file
|
@ -0,0 +1,19 @@
|
|||
const std = @import("std");
|
||||
const BufferInfo = @import("../../types/UserType.zig").BufferInfo;
|
||||
const writeInt = @import("../writeInt.zig").writeInt;
|
||||
const writeShort = @import("../writeShort.zig").writeShort;
|
||||
const writeByte = @import("../writeByte.zig").writeByte;
|
||||
const writeQByteArray = @import("../writeQByteArray.zig").writeQByteArray;
|
||||
|
||||
pub fn writeBufferInfo(writer: anytype, bufferInfo: BufferInfo) !void {
|
||||
try writeQByteArray(writer, "BufferInfo\x00");
|
||||
try writeInt(writer, bufferInfo.ID);
|
||||
try writeInt(writer, bufferInfo.NetworkID);
|
||||
try writeShort(writer, bufferInfo.Type);
|
||||
// 4 undocumented bytes.
|
||||
try writeByte(writer, 0x00);
|
||||
try writeByte(writer, 0x00);
|
||||
try writeByte(writer, 0x00);
|
||||
try writeByte(writer, 0x00);
|
||||
try writeQByteArray(writer, bufferInfo.Name);
|
||||
}
|
14
src/qtshit/write/usertypes/writeUserType.zig
Normal file
14
src/qtshit/write/usertypes/writeUserType.zig
Normal file
|
@ -0,0 +1,14 @@
|
|||
const std = @import("std");
|
||||
const UserType = @import("../../types/UserType.zig").UserType;
|
||||
const writeBufferInfo = @import("./writeBufferInfo.zig").writeBufferInfo;
|
||||
|
||||
pub fn writeUserType(writer: anytype, allocator: *std.mem.Allocator, usertype: UserType) !void {
|
||||
switch (usertype) {
|
||||
.BufferInfo => |value| {
|
||||
try writeBufferInfo(writer, value);
|
||||
},
|
||||
else => {
|
||||
@panic("Unsupported!");
|
||||
},
|
||||
}
|
||||
}
|
|
@ -13,6 +13,8 @@ const writeQVariantList = @import("./writeQVariantList.zig").writeQVariantList;
|
|||
const writeQVariantHeader = @import("./writeQVariantHeader.zig").writeQVariantHeader;
|
||||
const writeQVariantMap = @import("./writeQVariantMap.zig").writeQVariantMap;
|
||||
const writeQStringList = @import("./writeQStringList.zig").writeQStringList;
|
||||
const writeUserType = @import("./usertypes/writeUserType.zig").writeUserType;
|
||||
|
||||
|
||||
pub fn writeQVariant(writer: anytype, allocator: *std.mem.Allocator, variant: QVariantType) (@TypeOf(writer).Error || std.os.WriteError || error{OutOfMemory} || error{InvalidUtf8})!void {
|
||||
try writeQVariantHeader(writer, try QVariantTypeID(variant));
|
||||
|
@ -47,8 +49,8 @@ pub fn writeQVariant(writer: anytype, allocator: *std.mem.Allocator, variant: QV
|
|||
.QDateTime => {
|
||||
@panic("Can't write QDateTime");
|
||||
},
|
||||
.UserType => {
|
||||
@panic("Can't write UserTypes");
|
||||
.UserType => |out| {
|
||||
try writeUserType(writer, allocator, out);
|
||||
},
|
||||
//else => {
|
||||
// @panic("Unsupported!");
|
||||
|
|
Loading…
Reference in a new issue