Created
July 28, 2013 06:34
-
-
Save alexey-gamov/6097660 to your computer and use it in GitHub Desktop.
Модуль для отправки сообщений в локальной сети. Сервер не требуется, т.к. сообщение отправляется в глобальном пакете.
Для настройки защиты в блоке const нужно настроить переменные salt (соль) и pass (пароль)..
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
(* | |
LAN module by XProger | |
Security addon by atomos.pro | |
version: 0.2b | |
*) | |
unit Net; | |
interface | |
const | |
salt = 'hackme'; | |
pass = 85; | |
{ Инициализация сети - Если в результате получаем false, значит произошли ошибки } | |
function NET_Init: Boolean; | |
{ Высвобождение ресурсов под сеть } | |
procedure NET_Free; | |
{ Очистка буфера записи -т.е. сначала нужно очистить буфер, затем записать в него | |
данные при помощи NET_Write и послать их через NET_Send | |
после отправки буфер не очищается, т.е. можно ещё раз | |
вызвать NET_Write и послать этот же буфер кому-то другому } | |
procedure NET_Clear; | |
{ Инициализирует сокет на указанном порту, если значене порта выставленно в 0, то выбирается | |
любой свободный порт. Возвращает идентификатор сокета. Сокет всего один, т.к. для большинства задач больше и не нужно ;) } | |
function NET_InitSocket(Port: WORD): Integer; | |
{ Записывает Count байт из Buf (указатель на что-либо) в буфер исходящих данных } | |
function NET_Write(Buf: Pointer; Count: Integer): Boolean; | |
{ Отправляет данные содержащиеся в исходящем буфере на отправку по указанному IP адресу и Port. | |
В случае если IP = nil посылается широковещательный пакет (только локальные сети) | |
APL (Anti Packet Lost) указывает, нужна ли гарантированная доставка для этих данных | |
которая не работает для широковещательных рассылок :) } | |
function NET_Send(IP: PChar; Port: WORD; APL: Boolean): Integer; | |
{ Вытащить Count байт из входящего буфера пакетов | |
Count желательно указывать максимально большим, т.к. не прочитанные из пакета данные будут утеряны | |
В IP и Port записываются IP адрес и порт компьютера приславшего пакет | |
Результат - кол-во полученных байт, также записывается в RecvBytes | |
Рекомендуется производить проверку пришедших данных как можно чаще (например, раз в тик игрового цикла) | |
вызывать эту функцию нужно до тех пор, пока RecvBytes (или результат) превышают 0 байт :) } | |
function NET_Recv(Buf: Pointer; Count: Integer; var IP: PChar; var Port: Integer; var RecvBytes: Integer): Integer; | |
implementation | |
uses | |
Windows, WinSock, StrUtils; | |
const | |
MaxBufLen = 65507; | |
type | |
TByteArray = array [0..1024] of Byte; | |
PByteArray = ^TByteArray; | |
var | |
NET_Ready : Boolean = False; // инициализированна ли сеть | |
NET_Buf : PByteArray; // сам буфер-накопитель | |
NET_BufLen : Integer; // текущая длинна буфера | |
NET_Socket : Integer = -1; | |
NET_trys : Byte = 4; | |
regseek : Integer = 0; | |
var | |
NET_tmpBuf : PByteArray; | |
function Encrypt(s: String; code: Boolean): String; | |
var | |
i, Delta, Res: Integer; | |
begin | |
Result := ''; | |
for i := 1 to Length(s) do | |
begin | |
Delta := ((i xor pass) mod 256); | |
if not code then | |
begin | |
Res := Ord(s[i]) - Delta - 32; | |
if Res < 32 then Res := Res + 256; | |
end | |
else Res := ((Ord(s[i]) + Delta) mod 256) + 32; | |
Result := Result + chr(Res); | |
end; | |
end; | |
procedure NET_Free; | |
begin | |
if NET_Ready then | |
begin | |
if NET_Socket > 0 then CloseSocket(NET_Socket); | |
NET_Socket := -1; | |
FreeMem(NET_Buf); | |
FreeMem(NET_tmpBuf); | |
NET_Buf := nil; | |
NET_tmpBuf := nil; | |
WSACleanup; | |
NET_Ready := False; | |
end; | |
end; | |
procedure NET_Clear; | |
begin | |
NET_BufLen := 1; | |
end; | |
function NET_Init: Boolean; | |
var | |
winsock_version : WORD; | |
winsock_data : WsaData; | |
error : Integer; | |
begin | |
Result := False; | |
NET_Free; | |
NET_Ready := False; | |
winsock_version := MAKEWORD(1, 1); | |
error := WSAStartup(winsock_version, winsock_data); | |
if error <> 0 then Exit; | |
NET_Ready := True; | |
NET_Clear; | |
NET_Socket := -1; | |
if NET_Buf = nil then GetMem(NET_Buf, MaxBufLen); | |
if NET_tmpBuf = nil then GetMem(NET_tmpBuf, MaxBufLen); | |
Result := True; | |
end; | |
function NET_InitSocket(Port: WORD): Integer; | |
var | |
sock : Integer; | |
flag : Integer; | |
i : Integer; | |
address : SockAddr_in; | |
begin | |
Result := 0; | |
i := 1; | |
flag := 1; | |
if NET_Socket > 0 then CloseSocket(NET_Socket); | |
// создаем UDP socket | |
sock := socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP); | |
if sock = -1 then Exit; | |
// устанавливаем параметр nonblocking для socket, что означает, что если на | |
// входе нет данных, то метод чтения не будет ждать их появления | |
if IoctlSocket(sock, FIONBIO, flag) = -1 then Exit; | |
// настраиваем socket так, чтобы была возможность посылать и принимать broadcast | |
// сообщения, то есть, сообщения, направленные всем сетевым клиентам в текущей | |
// локальной сети | |
SetSockOpt(sock, SOL_SOCKET, SO_BROADCAST, PChar(@i), SizeOf(i)); | |
address.sin_addr.S_addr := INADDR_ANY; | |
address.sin_port := htons(Port); | |
address.sin_family := AF_INET; | |
// "прикрепляем" socket к порту | |
if bind(sock, address, sizeof(address)) = -1 then | |
begin | |
CloseSocket(sock); | |
Exit; | |
end; | |
NET_Socket := sock; | |
Result := sock; | |
end; | |
function NET_Write(Buf: Pointer; Count: Integer): Boolean; | |
var | |
i : Integer; | |
begin | |
Result := False; | |
// добавим соли в buf | |
Buf := Pointer(PChar(Encrypt(PChar(Buf) + salt, False))); | |
Count := Length(PChar(Buf)); | |
if (not NET_Ready) or (NET_Socket <= 0) then Exit; | |
if Count <= 0 then Exit; | |
if NET_BufLen + Count < MaxBufLen then | |
begin | |
for i := Net_BufLen to Net_BufLen + Count - 1 do | |
NET_Buf[i] := PByteArray(buf)[i - Net_BufLen]; | |
NET_BufLen := NET_BufLen + Count; | |
Result := True; | |
end; | |
end; | |
function NET_Recv(Buf: Pointer; Count: Integer; var IP: PChar; var Port: Integer; var RecvBytes: Integer): Integer; | |
var | |
from : sockaddr_in; | |
i : Integer; | |
s : String; | |
begin | |
Result := 0; | |
if (not NET_Ready) or (NET_Socket <= 0) then Exit; | |
if (Count <= 0) or (Count > MaxBufLen) then Exit; | |
i := SizeOf(from); | |
Result := recvfrom(NET_Socket, NET_tmpBuf[0], Count, 0, from, i); | |
if Result <= 0 then | |
begin | |
Result := -1; | |
RecvBytes := Result; | |
Exit; | |
end; | |
dec(Result); | |
if Result > 0 then | |
begin | |
IP := inet_ntoa(from.sin_addr); | |
Port := ntohs(from.sin_port); | |
if NET_tmpBuf[0] = 0 then | |
begin | |
// запишем полученное в строку s и расшифруем | |
SetString(s, PAnsiChar(@NET_tmpBuf[1]), Result); | |
s := Encrypt(s, True); | |
// проверим на содержание соли и удалим её вконце | |
if RightStr(s, Length(salt)) <> salt then Result := 0 | |
else begin | |
Move(s[1], PByteArray(buf)[0], Length(s) - Length(salt)); | |
Result := Result - Length(salt); | |
end; | |
end; | |
end; | |
RecvBytes := Result; | |
end; | |
function NET_Send(IP: PChar; Port: WORD; APL: Boolean): Integer; | |
var | |
address : sockaddr_in; | |
begin | |
Result := 0; | |
if (not NET_Ready) or (NET_Socket <= 0) then Exit; | |
address.sin_family := AF_INET; | |
address.sin_port := htons(Port); | |
if IP <> nil then address.sin_addr.S_addr := inet_addr(IP) | |
else address.sin_addr.S_addr := INADDR_BROADCAST; | |
FillChar(address.sin_zero, SizeOf(address.sin_zero), 0); | |
if IP = nil then | |
begin | |
NET_Buf[0] := 0; | |
Result := SendTo(NET_Socket, NET_Buf[0], NET_BufLen, 0, address, SizeOf(address)); | |
end; | |
end; | |
end. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
unit usage; | |
interface | |
uses | |
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, | |
Dialogs, StdCtrls, Net; | |
type | |
TForm1 = class(TForm) | |
Timer1: TTimer; | |
Memo1: TMemo; | |
procedure TForm1.FormCreate(Sender: TObject); | |
procedure TForm1.FormDestroy(Sender: TObject); | |
procedure TForm1.Timer1Timer(Sender: TObject); | |
end; | |
var | |
Form1: TForm1; | |
Message: String; | |
implementation | |
{$R *.dfm} | |
{ функция отправки сообщения } | |
function SendMessage(Edit: String): String; | |
begin | |
Message := Edit; | |
NET_Clear; | |
NET_Write(@Message[1], Length(Message)); | |
NET_Send(nil, 21666, False); | |
end; | |
{ инициализация чата} | |
procedure TForm1.FormCreate(Sender: TObject); | |
begin | |
if not NET_Init then | |
begin | |
MessageBox(Handle, 'Невозможно инициализировать сетевой протокол', 'Ошибка', MB_ICONHAND); | |
Halt; | |
end; | |
NET_InitSocket(21666); | |
SendMessage('hello chat!'); | |
end; | |
procedure TForm1.FormDestroy(Sender: TObject); | |
begin | |
NET_Free; | |
end; | |
{ получение сообщения } | |
procedure TForm1.Timer1Timer(Sender: TObject); | |
var | |
buf: array [0..255] of Char; | |
Port, recv, i: Integer; | |
IP: PChar; | |
Message: String; | |
begin | |
// получим сообщение через рекурсивную фукцию | |
while NET_Recv(@buf, 255, IP, Port, recv) > 0 do | |
begin | |
Message := Copy(buf, 1, recv); | |
Memo1.Items.Add(Message); | |
end; | |
end; | |
end. |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment