SRL Archive - Non-RuneScape Scripts

Messing With Simba Sockets.


Brandon

2013-01-03 00:59:57

I've been messing with Simba's untouched functions and API's lately and decided to mess around with Sockets to Send and Receive Emails, Download Pages and Files. Literally almost everything. Only thing I haven't tried yet is SQL connections.. Also only some emails seem to work.. Something to do with SSL..

Here's some Snippets you guys can use/run.. The following can read from a socket one line at a time or all at once, all the headers, chunk encoded data and any data given the right headers. The example code will download a PNG file I randomly chose from Imgur to your Simba folder..

If you want, you can also PacketSniff with it given the right information and requests. You can also set your own User-Agent and Referral site as well. It's pretty fast. Took only 27ms to run the code on my crappy internet.

Iunno where the Snippets section is or what section this would go in but meh..

Function RecvLine(Socket: Integer): String;
var
Character, Line: String;
Begin
While(True) Do
Begin
Character := RecvSocketEx(Socket, 1);

If (Character = #13) Then
Begin
Character := RecvSocketEx(Socket, 1);
If (Character = #10) Then Break;

Line := Line + #13;
End Else
If (Character = #10) Then Break;

Line := Line + Character;
End;

Result := Line;
End;

Function RecvHeader(Socket: Integer): TStringArray;
var
I: Integer;
Line: String;
Begin
While(True) Do
Begin
Line := RecvLine(Socket);
If (Length(Line) = 0) Then Exit;

SetLength(Result, Length(Result) + 1);
Result[I] := Line;
Inc(I);
End;
End;

Function FindHeaderValue(LineToFind: String; Header: TStringArray): String;
var
I, H, Position: Integer;
Begin
H := High(Header);

For I := 0 To H Do
Begin
Position := Pos(':', Header[I]);
If ((Position > 0) And (Copy(Header[I], 0, Position - 1) = LineToFind)) Then
Begin
Position := Pos(' ', Header[I]);
If (Position <> 0) Then
Begin
Result := Copy(Header[I], Position + 1, Length(Header[I]) - Position);
Exit;
End;
End;
End;
End;

Function RecvChunkSize(Socket: Integer): Integer;
var
Line: String;
Position: Integer;
Begin
Line := RecvSocketStr(Socket);
Position := Pos(';', Line);
If (Position <> 0) Then
Delete(Line, Position, 1);

Result := HexToInt(Line);
End;

Function GetPageSocket(WebPage, Port: String): String;
var
Header: TStringArray;
Socket, ChunkLength: Integer;
Request, Encoding, Data, Buffer: String;
Begin
WebPage := Replace(WebPage, 'http://', '', [rfIgnoreCase, rfReplaceAll]);
WebPage := Replace(WebPage, 'https://', '', [rfIgnoreCase, rfReplaceAll]);

Request := 'GET / HTTP/1.1' + #13#10;
Request := Request + 'Host: ' + WebPage + #13#10;
Request := Request + 'Connection: close' + #13#10;
Request := Request + 'User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.11 (KHTML, like Gecko) Chrome/23.0.1271.97 Safari/537.11' + #13#10;
Request := Request + 'Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8' + #13#10;
Request := Request + 'Accept-Language: en-US,en;q=0.8' + #13#10;
Request := Request + 'Accept-Charset: ISO-8859-1,UTF-8;q=0.7,*;q=0.7' + #13#10;
Request := Request + 'Cache-Control: no-cache' + #13#10;
Request := Request + #13#10;

Socket := CreateSocket;
ConnectSocket(Socket, WebPage, Port);

SendSocket(Socket, Request);
Header := RecvHeader(Socket);

Encoding := FindHeaderValue('Transfer-Encoding', Header);

If (Encoding = 'chunked') Then
Begin
ChunkLength := RecvChunkSize(Socket);
While(ChunkLength <> 0) Do
Begin
Data := Data + RecvSocketEx(Socket, ChunkLength);
RecvLine(Socket);
ChunkLength := RecvChunkSize(Socket);
End;
End Else
Begin
Encoding := FindHeaderValue('Content-Length', Header);
If (Length(Encoding) > 0) Then
Begin
ChunkLength := StrToIntDef(Encoding, -1);
If (ChunkLength > 0) Then
Data := RecvSocketEx(Socket, ChunkLength);
End Else
Begin
While(True) Do
Begin
Buffer := RecvSocketEx(Socket, 1024);
If (Length(Buffer) = 0) Then Break;
Data := Data + Copy(Buffer, 0, Length(Buffer));
End;
End;
End;

CloseSocket(Socket);
FreeSocket(Socket);
Result := Data;
End;

Function DownloadFile(WebPage, Port, SaveAsPath: String): Boolean;
var
Header: TStringArray;
FileDownloaded: Integer;
Socket, Position, ChunkLength: Integer;
Host, FileLocation, Request, Encoding, Buffer, Data: String;
Begin
WebPage := Replace(WebPage, 'http://', '', [rfIgnoreCase, rfReplaceAll]);
WebPage := Replace(WebPage, 'https://', '', [rfIgnoreCase, rfReplaceAll]);
If (ExtractFileExt(WebPage) <> ExtractFileExt(SaveAsPath)) Then Exit;

Position := Pos('/', WebPage);
If (Position = 0) Then Exit;

Host := Copy(WebPage, 0, Position - 1);
FileLocation := Copy(WebPage, Position + 1, Length(WebPage) - Position);

Request := 'GET /' + FileLocation + ' HTTP/1.1' + #13#10;
Request := Request + 'Host: ' + Host + #13#10;
Request := Request + 'Connection: close' + #13#10;
Request := Request + 'User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.11 (KHTML, like Gecko) Chrome/23.0.1271.97 Safari/537.11' + #13#10;
Request := Request + 'Cache-Control: no-cache' + #13#10;
Request := Request + #13#10;

Socket := CreateSocket;
ConnectSocket(Socket, Host, Port);

SendSocket(Socket, Request);
Header := RecvHeader(Socket);

Encoding := FindHeaderValue('Content-Length', Header);

If (Encoding = 'chunked') Then
Begin
ChunkLength := RecvChunkSize(Socket);
While(ChunkLength <> 0) Do
Begin
Data := Data + RecvSocketEx(Socket, ChunkLength);
RecvLine(Socket);
ChunkLength := RecvChunkSize(Socket);
End;
End Else
Begin
Encoding := FindHeaderValue('Content-Length', Header);
If (Length(Encoding) > 0) Then
Begin
ChunkLength := StrToIntDef(Encoding, -1);
If (ChunkLength > 0) Then
Data := RecvSocketEx(Socket, ChunkLength);
End Else
Begin
While(True) Do
Begin
Buffer := RecvSocketEx(Socket, 1024);
If (Length(Buffer) = 0) Then Break;
Data := Data + Copy(Buffer, 0, Length(Buffer));
End;
End;
End;

CloseSocket(Socket);
FreeSocket(Socket);

FileDownloaded := CreateFile(SaveAsPath);
If (FileDownloaded <> -1) Then
Begin
WriteFileString(FileDownloaded, Data);
CloseFile(FileDownloaded);
Result := True;
End;
End;


begin
DownloadFile('http://i.imgur.com/AgLG0.png', '80', 'Foo.png');
end.

rj

2013-01-03 01:32:40

Seems pretty complicated didn't understand much but this:
DownloadFile('http://i.imgur.com/AgLG0.png', '80', 'Foo.png');
URL/Port/Save file name/File type

Atleast I think..


Lol nice work though

Kevin

2013-06-10 15:36:39

Well then. I was legitimately about to look into writing some of this only to see it's already here.

Only being familiar with sockets from a C/++ standpoint, I assume PascalScript can create socket connections based on IP addresses as well, correct?

Brandon

2013-06-10 19:48:24

From: Kevin
Well then. I was legitimately about to look into writing some of this only to see it's already here.

Only being familiar with sockets from a C/++ standpoint, I assume PascalScript can create socket connections based on IP addresses as well, correct?




Well then you might want to take a look at this? It's the C++ source I wrote about a year ago and decided to translate it to Simba to test if it works..

Meh.. Yeah Simba can connect to IP's but its limited; Which is why I stopped messing with anything socket-wise in Simba.. There's no Asynchronous sockets in Simba or SSL or anything.. There's way too many limitations to do anything, but the following might interest you:


std::uint32_t RecvEx(SOCKET Socket, void* Buffer, std::uint32_t BufferLength)
{
char* Pointer = reinterpret_cast<char*>(Buffer);
std::uint32_t TotalRead = 0;

while (BufferLength > 0)
{
int BytesRead = recv(Socket, Pointer, std::min(1024 * 1024, static_cast<int>(BufferLength)), 0);
if (BytesRead < 0)
{
if ((BytesRead == SOCKET_ERROR) && (WSAGetLastError() == WSAEWOULDBLOCK))
continue;

throw std::runtime_error("Error! RecvEx: Failed To Read Bytes.");
}

if (BytesRead == 0) break;

Pointer += BytesRead;
BufferLength -= BytesRead;
TotalRead += BytesRead;
}

return TotalRead;
}

std::string RecvLine(SOCKET Socket)
{
char Character = 0;
std::string Line;

while(true)
{
RecvEx(Socket, &Character, 1);

if (Character == '\r')
{
RecvEx(Socket, &Character, 1);
if (Character == '\n') break;
Line += '\r';
}
else if (Character == '\n') break;

Line += Character;
}
return Line;
}

void RecvHeaders(SOCKET Socket, std::vector<std::string>* Header)
{
while(true)
{
std::string Line = RecvLine(Socket);
if (Line.size() == 0) return;
if (Header) Header->push_back(Line);
}
}

std::string FindHeader(const std::string &LineToFind, const std::vector<std::string> &Header)
{
for (std::size_t I = 0; I < Header.size(); ++I)
{
int Position = Pos(":", Header[I]);
if ((Position != -1) && !Header[I].compare(0, Position, LineToFind))
{
Position = PosFirstNotOf(" ", Header[I], Position + 1);
if (Position != -1)
return Header[I].substr(Position);
}
}
return std::string();
}

std::uint32_t RecvChunkSize(SOCKET Socket)
{
std::string Line = RecvLine(Socket);
int Position = Pos(";", Line);
if (Position != -1) Line.erase(Position);

char* NextCharacter;
std::uint32_t Value = strtoul(Line.c_str(), &NextCharacter, 16);

return (*NextCharacter == '\0') ? Value : -1;
}


void GetPage(std::string WebPage, std::string SavePath)
{
WSADATA wsaData;
string Address;
struct addrinfo *result;
struct sockaddr_in *sockaddr_ipv4;

string Request = "GET / HTTP/1.1\r\n";
Request += "Host: " + WebPage + "\r\n";
Request += "Connection: close\r\n";
Request += "User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.11 (KHTML, like Gecko) Chrome/23.0.1271.97 Safari/537.11\r\n";
Request += "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8\r\n";
Request += "Accept-Language: en-US,en;q=0.8\r\n";
Request += "Accept-Charset: ISO-8859-1,UTF-8;q=0.7,*;q=0.7\r\n";
Request += "Accept-Encoding: \r\n";
Request += "Cache-Control: no-cache\r\n";
Request += "\r\n";

if (WSAStartup(MAKEWORD(2,2), &wsaData) != 0) return;

SOCKET Socket = socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);

getaddrinfo(WebPage.c_str(), NULL, NULL, &result);
if (result->ai_family == AF_INET)
{
sockaddr_ipv4 = (struct sockaddr_in *) result->ai_addr;
Address = inet_ntoa(sockaddr_ipv4->sin_addr);
}
freeaddrinfo(result);


SOCKADDR_IN SockAddr;
memset(&SockAddr, 0, sizeof(SockAddr));
SockAddr.sin_port = htons(80);
SockAddr.sin_family = AF_INET;
SockAddr.sin_addr.s_addr = inet_addr(Address.c_str());

if(connect(Socket,(SOCKADDR*)(&SockAddr),sizeof(SockAddr)) == SOCKET_ERROR) return;

if (send(Socket, Request.c_str(), Request.size(), 0) == SOCKET_ERROR) return;
shutdown(Socket, SD_SEND);

std::vector<std::string> Headers;
std::vector<unsigned char> Data;
RecvHeaders(Socket, &Headers);

std::string Encoding = FindHeader("Transfer-Encoding", Headers);
if (Encoding == "chunked")
{
std::uint32_t ChunkLength = RecvChunkSize(Socket);

while (ChunkLength)
{
size_t Offset = Data.size();
Data.resize(Offset + ChunkLength);
RecvEx(Socket, &Data[Offset], ChunkLength);
RecvLine(Socket);
ChunkLength = RecvChunkSize(Socket);
}
}
else
{
std::string HeaderValue = FindHeader("Content-Length", Headers);
if (HeaderValue.size())
{
std::uint32_t ContentLength = ToNumber<std::uint32_t>(HeaderValue);

if (ContentLength > 0)
{
Data.resize(ContentLength);
RecvEx(Socket, &Data[0], ContentLength);
}
}
else
{
std::uint8_t Buffer[1024] = {0};

while(true)
{
std::uint32_t BytesRead = RecvEx(Socket, Buffer, sizeof(Buffer));
if (BytesRead == 0) break;

std::size_t Offset = Data.size();
Data.resize(Offset + BytesRead);
std::memcpy(&Data[Offset], Buffer, BytesRead);
}
}
}

closesocket(Socket);
WSACleanup();

std::string Response = Replace(std::string(Data.begin(), Data.end()), "\r", "", ReplaceAll);

std::fstream hFile(SavePath.c_str(), std::ios::out);
hFile<<Response;
hFile.close();
}

Dgby714

2013-06-10 20:40:29

From: Brandon
Well then you might want to take a look at this? It's the C++ source I wrote about a year ago and decided to translate it to Simba to test if it works..

Meh.. Yeah Simba can connect to IP's but its limited; Which is why I stopped messing with anything socket-wise in Simba.. There's no Asynchronous sockets in Simba or SSL or anything.. There's way too many limitations to do anything, but the following might interest you:


std::uint32_t RecvEx(SOCKET Socket, void* Buffer, std::uint32_t BufferLength)
{
char* Pointer = reinterpret_cast<char*>(Buffer);
std::uint32_t TotalRead = 0;

while (BufferLength > 0)
{
int BytesRead = recv(Socket, Pointer, std::min(1024 * 1024, static_cast<int>(BufferLength)), 0);
if (BytesRead < 0)
{
if ((BytesRead == SOCKET_ERROR) && (WSAGetLastError() == WSAEWOULDBLOCK))
continue;

throw std::runtime_error("Error! RecvEx: Failed To Read Bytes.");
}

if (BytesRead == 0) break;

Pointer += BytesRead;
BufferLength -= BytesRead;
TotalRead += BytesRead;
}

return TotalRead;
}

std::string RecvLine(SOCKET Socket)
{
char Character = 0;
std::string Line;

while(true)
{
RecvEx(Socket, &Character, 1);

if (Character == '\r')
{
RecvEx(Socket, &Character, 1);
if (Character == '\n') break;
Line += '\r';
}
else if (Character == '\n') break;

Line += Character;
}
return Line;
}

void RecvHeaders(SOCKET Socket, std::vector<std::string>* Header)
{
while(true)
{
std::string Line = RecvLine(Socket);
if (Line.size() == 0) return;
if (Header) Header->push_back(Line);
}
}

std::string FindHeader(const std::string &LineToFind, const std::vector<std::string> &Header)
{
for (std::size_t I = 0; I < Header.size(); ++I)
{
int Position = Pos(":", Header[I]);
if ((Position != -1) && !Header[I].compare(0, Position, LineToFind))
{
Position = PosFirstNotOf(" ", Header[I], Position + 1);
if (Position != -1)
return Header[I].substr(Position);
}
}
return std::string();
}

std::uint32_t RecvChunkSize(SOCKET Socket)
{
std::string Line = RecvLine(Socket);
int Position = Pos(";", Line);
if (Position != -1) Line.erase(Position);

char* NextCharacter;
std::uint32_t Value = strtoul(Line.c_str(), &NextCharacter, 16);

return (*NextCharacter == '\0') ? Value : -1;
}


void GetPage(std::string WebPage, std::string SavePath)
{
WSADATA wsaData;
string Address;
struct addrinfo *result;
struct sockaddr_in *sockaddr_ipv4;

string Request = "GET / HTTP/1.1\r\n";
Request += "Host: " + WebPage + "\r\n";
Request += "Connection: close\r\n";
Request += "User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.11 (KHTML, like Gecko) Chrome/23.0.1271.97 Safari/537.11\r\n";
Request += "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8\r\n";
Request += "Accept-Language: en-US,en;q=0.8\r\n";
Request += "Accept-Charset: ISO-8859-1,UTF-8;q=0.7,*;q=0.7\r\n";
Request += "Accept-Encoding: \r\n";
Request += "Cache-Control: no-cache\r\n";
Request += "\r\n";

if (WSAStartup(MAKEWORD(2,2), &wsaData) != 0) return;

SOCKET Socket = socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);

getaddrinfo(WebPage.c_str(), NULL, NULL, &result);
if (result->ai_family == AF_INET)
{
sockaddr_ipv4 = (struct sockaddr_in *) result->ai_addr;
Address = inet_ntoa(sockaddr_ipv4->sin_addr);
}
freeaddrinfo(result);


SOCKADDR_IN SockAddr;
memset(&SockAddr, 0, sizeof(SockAddr));
SockAddr.sin_port = htons(80);
SockAddr.sin_family = AF_INET;
SockAddr.sin_addr.s_addr = inet_addr(Address.c_str());

if(connect(Socket,(SOCKADDR*)(&SockAddr),sizeof(SockAddr)) == SOCKET_ERROR) return;

if (send(Socket, Request.c_str(), Request.size(), 0) == SOCKET_ERROR) return;
shutdown(Socket, SD_SEND);

std::vector<std::string> Headers;
std::vector<unsigned char> Data;
RecvHeaders(Socket, &Headers);

std::string Encoding = FindHeader("Transfer-Encoding", Headers);
if (Encoding == "chunked")
{
std::uint32_t ChunkLength = RecvChunkSize(Socket);

while (ChunkLength)
{
size_t Offset = Data.size();
Data.resize(Offset + ChunkLength);
RecvEx(Socket, &Data[Offset], ChunkLength);
RecvLine(Socket);
ChunkLength = RecvChunkSize(Socket);
}
}
else
{
std::string HeaderValue = FindHeader("Content-Length", Headers);
if (HeaderValue.size())
{
std::uint32_t ContentLength = ToNumber<std::uint32_t>(HeaderValue);

if (ContentLength > 0)
{
Data.resize(ContentLength);
RecvEx(Socket, &Data[0], ContentLength);
}
}
else
{
std::uint8_t Buffer[1024] = {0};

while(true)
{
std::uint32_t BytesRead = RecvEx(Socket, Buffer, sizeof(Buffer));
if (BytesRead == 0) break;

std::size_t Offset = Data.size();
Data.resize(Offset + BytesRead);
std::memcpy(&Data[Offset], Buffer, BytesRead);
}
}
}

closesocket(Socket);
WSACleanup();

std::string Response = Replace(std::string(Data.begin(), Data.end()), "\r", "", ReplaceAll);

std::fstream hFile(SavePath.c_str(), std::ios::out);
hFile<<Response;
hFile.close();
}


I am planning on adding non-blocking sockets, just give me some time, I have a lot on my todo list.

SSL, We may already have this, do you have OpenSSL installed?

Brandon

2013-06-10 21:18:10

From: Dgby714
I am planning on adding non-blocking sockets, just give me some time, I have a lot on my todo list.

SSL, We may already have this, do you have OpenSSL installed?



Ahh yes. I am well aware that you were working on something from our last thread on sockets. Just saying that at the moment, it's useless to do anything socket-wise in Simba as the sockets are pretty down-played.. Probably why most mail functions use a middle-man website? Yes I have OpenSSL. Meh take your time. No rush from me as I have other things I'd prefer to work on.

Flight

2013-06-10 21:35:50

Dgby714, I've tried using your past DownloadToFile function from a while back and I was wondering if you could shoot some advice my way. I'd like to download a full Zipped package from Github directly using your function but there's an error while doing so with:

FileC := GetHTTPPage(FileI, URL);
FileH := GetRawHeaders(FileI);

Is it even possible to download, via a function, from Github?

Brandon I might gives yours a shot and see what I come up with.

Dgby714

2013-06-11 11:09:56

From: Flight
Dgby714, I've tried using your past DownloadToFile function from a while back and I was wondering if you could shoot some advice my way. I'd like to download a full Zipped package from Github directly using your function but there's an error while doing so with:

FileC := GetHTTPPage(FileI, URL);
FileH := GetRawHeaders(FileI);

Is it even possible to download, via a function, from Github?

Brandon I might gives yours a shot and see what I come up with.


It will work fine, but GitHub requires https, so a client needs OpenSSL installed for it to work.

Also, try a mention next time so I see the post.

Kevin

2013-06-11 11:58:01

From: Dgby714
I am planning on adding non-blocking sockets, just give me some time, I have a lot on my todo list.

SSL, We may already have this, do you have OpenSSL installed?


I very much so look forward to non-blocking sockets! Many thanks for that work!

As for SSL, I know we have the dlls for it somewhere as I have them on (one of) my computer, but I have no idea where I originally found them.

Dgby714

2013-06-11 23:36:17

From: Kevin
I very much so look forward to non-blocking sockets! Many thanks for that work!

As for SSL, I know we have the dlls for it somewhere as I have them on (one of) my computer, but I have no idea where I originally found them.


I just needs the standard OpenSSL libraries.