====== Erlang - Lista 4. ======
===== Zadanie 2. =====
#!/usr/bin/env escript
main(_) ->
case io:get_line("") of
eof -> {error, read_error};
{error, Reason} -> {error, read_error, Reason};
Input -> analyze(hd_to_binary(Input))
end.
hd_to_binary(HD) -> hd_to_binary(HD, []).
hd_to_binary("\n", Acc) ->
list_to_binary(lists:reverse(Acc));
hd_to_binary([X,Y|HD], Acc) ->
{ok, [V], []} = io_lib:fread("~16u", [X,Y]),
hd_to_binary(HD, [V | Acc]).
binary_to_hd(Bin) ->
lists:flatten([io_lib:format("~2.16.0B", [X]) ||
X <- binary_to_list(Bin)]).
icmp(Payload) ->
case Payload of
<< ToM: 8, Code: 8, Checksum: 16, Quench: 32, Data/binary>> ->
Sum = chksum(<< ToM:8, Code:8, 0:16, Quench: 32, Data/binary>>),
io:format("\nICMP:\n\nType of message:\t0x~.16B (~s)\nCode:\t\t\t0x~.16B\nChecksum:\t\t0x~.16B (calculated: 0x~.16B)\nQuench:\t\t\t~.16B\nData:\t\t\t~s\n", [ToM, icmp_type(ToM), Code, Checksum, Sum, Quench, binary_to_hd(Data)]);
_ -> {error}
end.
udp(DGram, IP) ->
case DGram of
<< SPort: 16, DPort: 16, Len: 16, Checksum:16, Data/binary>> ->
Sum = chksum(<< IP/binary, SPort:16, DPort:16, Len:16, 0:16, Data/binary>>),
io:format("\nUDP:\n\nSource port:\t\t0x~.16B (~B)\nDestination port:\t0x~.16B (~B)\nLen:\t\t\t~B\nChecksum:\t\t0x~.16B (calculated: 0x~.16B)\nData:\t\t\t~s\n", [SPort, SPort, DPort, DPort, Len, Checksum, Sum, binary_to_hd(Data)]);
_ -> {error}
end.
tcp(Segment, SAddr, DAddr) ->
case Segment of
<< SPort: 16, DPort: 16, Seq: 32, Ack: 32, DataOff: 4, Reserved: 4, CWR:1, ECE:1, URG:1, ACK:1, PSH:1, RST:1, SYN:1, FIN:1, WindowSize: 16, Checksum: 16, UrgentPointer: 16, Data/binary>> ->
SegSize = byte_size(Segment),
Sum = chksum(<< SAddr:32, DAddr:32, 0:8, 6:8, SegSize:16, SPort: 16, DPort: 16, Seq: 32, Ack: 32, DataOff: 4, Reserved: 4, CWR:1, ECE:1, URG:1, ACK:1, PSH:1, RST:1, SYN:1, FIN:1, WindowSize: 16, 0:16, UrgentPointer:16, Data/binary>>),
io:format("\nTCP:\n\nSource port:\t\t0x~.16B (~B)\nDestination port:\t0x~.16B (~B)\nSequence number:\t~B\nAck number:\t\t~B\nData offset:\t\t0x~.16B\nFlags:\t\t\tCWR: ~B ECE: ~B URG: ~B ACK: ~B PSH: ~B RST: ~B SYN: ~B FIN: ~B\nWindow size:\t\t0x~.16B\nChecksum:\t\t0x~.16B (calculated: 0x~.16B)\nUrgent pointer:\t\t~.16B\nData:\t\t\t~s\n", [SPort, SPort, DPort, DPort, Seq, Ack, DataOff, CWR, ECE, URG, ACK, PSH, RST, SYN, FIN, WindowSize, Checksum, Sum, UrgentPointer, binary_to_hd(Data)]);
_ -> {error}
end.
analyze(Dgram) ->
DgramSize = byte_size(Dgram),
case Dgram of
<< 4:4, HLen:4, SrvcType:8, TotLen:16,
ID:16, Flgs:3, FragOff:13, TTL:8,
Proto:8, HdrChkSum:16, SrcIP:32, DestIP:32,
RestDgram/binary>>
% when HLen >= 5, 4*HLen=
OptsLen = 4*(HLen - 5),
<> = RestDgram,
CRC = chksum(<< 4:4, HLen:4, SrvcType:8, TotLen:16, ID:16, Flgs:3, FragOff:13, TTL:8, Proto:8, 0:16, SrcIP:32, DestIP:32, Opts:OptsLen>>),
io:format("IP version:\t\t4\nHeader length:\t\t~B\nService type:\t\t~B\nTotal length:\t\t~B (calculated: ~B)\nID:\t\t\t0x~.16B\nFlags:\t\t\t0x~.16B\nFragment offset:\t~B\nTTL:\t\t\t~B\nProtocol:\t\t0x~.16B (~s)\nHeader checksum:\t0x~.16B (calculated: 0x~.16B)\nSource address:\t\t0x~.16B (~s)\nDestination address:\t0x~.16B (~s)\nData:\t\t\t~s\n", [HLen, SrvcType, TotLen, DgramSize, ID, Flgs, FragOff, TTL, Proto, proto(Proto), HdrChkSum, CRC, SrcIP, hex_to_ip(SrcIP), DestIP, hex_to_ip(DestIP), binary_to_hd(Data)]),
if
Proto == 1 -> icmp(Data);
Proto == 6 -> tcp(Data, SrcIP, DestIP);
Proto == 17 -> DSize = byte_size(Data), udp(Data, <>);
true -> io:format("")
end;
_ -> io:format("Not an IP packet\n")
end.
hex_to_ip(H) ->
X = << H:32 >>,
<< A:8, B:8, C:8, D:8 >> = X,
io_lib:format("~B.~B.~B.~B", [A,B,C,D]).
proto(P) ->
Protos = [
{1, "ICMP"},
{3, "GGP"},
{6, "TCP"},
{17, "UDP"}
],
case lists:keyfind(P, 1, Protos) of
false -> "Unknown";
{_, Proto} -> Proto
end.
icmp_type(P) ->
Types = [
{0, "Echo reply"},
{1, "Reserved"},
{3, "Destination unreachable"},
{8, "Echo request"}
],
case lists:keyfind(P, 1, Types) of
false -> "Unknown";
{_, Proto} -> Proto
end.
chksum(H) -> chksum(H, 0).
chksum(<<>>, Acc) -> (bnot (Acc + (Acc bsr 16)) band 65535);
chksum(<>, Acc) -> chksum(<>, Acc);
chksum(<>, Acc) ->
chksum(C, Acc+B+(A bsl 8)).
===== Zadanie 3. =====
-module(zad3).
-export([create/1, insert/2, select/2, select/3, delete/2, update/3, update/4]).
-record(db, {recordname, fields, auto_id, data}).
% test:
% rd(x, {y,z}).
%{db,a, [y,z], 4, [{1,#x{y = 1,z = 2}}, {2,#x{y = undefined,z = undefined}}, {3,#x{y = 5,z = 5}}]}
create({RecordName, Fields}) ->
{ok, #db{recordname=RecordName, fields=Fields, auto_id=1, data=[]}}.
insert(Db, Record) ->
Id = Db#db.auto_id,
NewData = [{Id,Record}|Db#db.data],
{ok, Id, Db#db{auto_id=Id+1, data=NewData}}.
select(Db, Pred) ->
try
Result = lists:filter(fun ({_,Record}) -> Pred(Record) end, Db#db.data),
{ok, Result}
catch
_:_ -> {error, bad_query}
end.
select(Db, Pred, Field) ->
try
N = field(Field, Db#db.fields),
Result = lists:filter(fun ({_,Record}) -> Pred(element(N,Record)) end, Db#db.data),
{ok, Result}
catch
_:_ -> {error, bad_query}
end.
field(Field, Fields) ->
field(Field, Fields, 2).
field(_, [], _) -> {error, not_found};
field(Field, [H|L], N) ->
if
Field == H -> N;
true -> field(Field, L, N+1)
end.
delete(Db, Pred) ->
try
{Sat, NSat} = lists:partition(fun ({_,Record}) -> Pred(Record) end, Db#db.data),
{ok, Db#db{data=NSat}, Sat}
catch
_:_ -> {error, bad_query}
end.
update(Db, Pred, F) ->
try
{Sat, NSat} = lists:partition(fun ({_,Record}) -> Pred(Record) end, Db#db.data),
try
ModSat = lists:map(fun ({Id, Record}) -> {Id, F(Record)} end, Sat),
{ok, Db#db{data=ModSat++NSat}, ModSat}
catch
_:_ -> {error, bad_updater}
end
catch
_:_ -> {error, bad_query}
end.
update(Db, Pred, F, Field) ->
N = field(Field, Db#db.fields),
update(Db,
fun(P) -> Pred(element(N, P)) end,
fun(P) -> setelement(N, P, F(element(N, P))) end
).