I am adding telnet connections to a IRC bot I'm working on for my dual enrollment project, you can chat on telnet/IRC and it features dual moderation, yadda yadda I am not announcing a project I just need some help with my coding:
My code can connect and Send, but Receive cannot get the replied
My client is a Windows machine. From this I create a socket connection to an IP and a port on a server machine. On the client machine I can manually telnet to the server, Send/Receive message like this:
Send: telnet IP Port
Receive: Connected to IP...
Send: Operation=TotalRecords
Receive: TotalRecords=1000
The fact that I can connect/Send/Receive suggests there is no access issue (the server is a linux machine).
Now here is my socket code. I can Connect and Send ("Operation=TotalRecords"). But Receive keep on waiting but never getting the message "TotalRecords=1000".
How do I code to receive the reply?
IPAddress remoteIPAddress = IPAddress.Parse(LinuxIPAddress);
EndPoint ep = new IPEndPoint(remoteIPAddress, 4321);
Socket sock = new Socket(AddressFamily.InterNetwork,SocketType.Stream,ProtocolType.Tcp);
string query="Operation=TotalRecords";
sock.Connect(ep);
Encoding ASCII = Encoding.ASCII;
Byte[] ByteGet = ASCII.GetBytes(query);
Byte[] RecvBytes = new Byte[256];
int iTx=sock.Send(ByteGet, ByteGet.Length, 0); //the code worked to this point
Int32 bytes = sock.Receive(RecvBytes, RecvBytes.Length, 0); //this will wait forever...
C'mon, MindFyre, iago??
It's C++, based off of iago and DarkMinion's code, but it's pretty close to what I assume you want:
void h_socket::waitEvents()
{
long clientToken = GetTickCount();
char serverToken[4] = "";
char mpqFile[256] = "";
char checksumFormula[256];
char buffer[20000] = "";
char exeinfo[256] = "";
unsigned long version;
unsigned long checksum;
unsigned long *prodVal;
unsigned long *publicVal;
unsigned long *privateVal;
PacketBuffer pbuff;
send(s, "\x1", 1, 0);
pbuff.insert((int)0x00);
pbuff.insert(PLATID_IX86);
pbuff.insert(CLIENT_STAR);
pbuff.insert((int)0xcd);
pbuff.insert((int)0x00);
pbuff.insert((int)0x00);
pbuff.insert((int)0x00);
pbuff.insert((int)0x00);
pbuff.insert((int)0x00);
pbuff.insert("USA");
pbuff.insert("United States");
pbuff.sendpacket(s, 0x50);
while(bncsConnected)
{
DWORD waitresult = WaitForSingleObject(events[0], 10);
if(waitresult == WAIT_OBJECT_0)
{
int buflen = 0;
int packetlen = 0;
char packetdata[5000] = "";
int recvlen = recv(s, buffer + buflen, sizeof(buffer) - buflen, 0);
if(!recvlen || recvlen == SOCKET_ERROR)
{
bncsConnected = false;
Disconnect();
h_timestamp();
printf("socket closed; recvlen %i\n", recvlen);
break;
}
buflen += recvlen;
while((int)buflen >= 4 && bncsConnected && (unsigned char)buffer[0] == 0xff)
{
char packetid = buffer[1];
packetlen = *(unsigned short *)(buffer + 2);
memcpy(packetdata, buffer, packetlen);
switch(packetid)
{
case SID_NULL:
pbuff.sendpacket(s, SID_NULL);
break;
case SID_PING:
pbuff.insert((int)(*(unsigned long *)(buffer + 4)));
pbuff.sendpacket(s, 0x25);
break;
case SID_AUTH_INFO:
h_timestamp();
if(*(unsigned long *)(packetdata + 4) == 0)
{
printf("Logon type is broken SHA-1\n");
}else if(*(unsigned long *)(packetdata + 4) == 1) {
printf("Logon type is NLS 1; this should not be! Aborting logon\n");
Disconnect();
} else if(*(unsigned long *)(packetdata + 4) == 2) {
printf("Logon type is NLS 2\n");
}
strcpy(serverToken, packetdata + 8);
strcpy(mpqFile, packetdata + 24);
strcpy(checksumFormula, packetdata + 37);
h_timestamp();
printf("Server Token: 0x");
hexStr(4, serverToken);
printf("\n");
h_timestamp();
printf("MPQ File: %s\n", mpqFile);
h_timestamp();
printf("Checksum Formula: %s\n", checksumFormula);
pbuff.clear();
pbuff.insert((int)clientToken);
h_timestamp();
if(!CheckRevision(
".\\star\\starcraft.exe",
".\\star\\storm.dll",
".\\star\\battle.snp",
checksumFormula,
&version,
&checksum,
exeinfo,
mpqFile
))
{
printf("CheckRevision() call failed; invalid hashes\n");
Disconnect();
break;
}
printf("CheckRevision() call passed\n");
pbuff.insert(version);
pbuff.insert(checksum);
pbuff.insert((int)1);
pbuff.insert((int)0);
h_timestamp();
if(DecodeCDKey(cfg.cdkey, prodVal, publicVal, privateVal) == false)
{
printf("CD-Key decode failed\n");
Disconnect();
break;
}
printf("CD-Key decode passed\n");
pbuff.insert((int)strlen(cfg.cdkey));
pbuff.insert(*(unsigned long *)prodVal);
pbuff.insert(*(unsigned long *)publicVal);
pbuff.insert((int)0);
pbuff.insert(*(unsigned long *)privateVal);
break;
default:
hexDump(packetlen, packetdata);
}
ZeroMemory(buffer, 20000);
ZeroMemory(packetdata, 5000);
packetlen = 0;
}
}
}
return;
}
I have a hard time understanding that code but when I get on my other computer I'll see if it compiles and runs with my modules, which were written in C#, I don't know if it's totally cross platform.
You'll need more code than that. hexDump(), h_timestamp(), Disconnect() etc.. are in my other code somewhere, and you'll need windows.h and stdlib.h (maybe?) too.
This is becoming a pain in the rear. If you have all the includes please just zip them and send what I need to get a module running. My project is due soon, I will probly just slap a GUI on this and add it to the rest of my bot, I'm not trying to connect to battle.net, just telent and IRC.
Quote from: GameSnake on August 17, 2005, 01:03:58 PM
C'mon, MindFyre, iago??
OMG I didn't know this was anything to do with C#. Your topic title [C] threw me off.
You have a few different approaches to take.
The easiest is to use a NetworkStream object and then use a StreamReader/StreamWriter on top of it. For example (you need the following namespaces: System.Net, System.Net.Sockets, System.IO, System.Text, System.Threading):
private NetworkStream m_ns;
private StreamReader m_sr;
private StreamWriter m_sw;
private Thread m_tdListener;
private bool m_open;
public delegate void TextEventHandler(string text);
public event TextEventHandler TextReceived;
protected virtual void OnTextReceived(string text) {
if (TextReceived != null)
TextReceived(text);
}
public void Connect(EndPoint ep) {
Socket sck = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
m_ns = new NetworkStream(sck, true);
m_sr = new StreamReader(ns, Encoding.ASCII);
m_sw = new StreamWriter(ns, Encoding.ASCII);
sck.Connect(ep);
m_open = true;
m_tdListener = new Thread(new ThreadStart(SocketListenLoop));
m_tdListener.IsBackground = true;
m_tdListener.Priority = ThreadPriority.BelowNormal;
m_tdListener.Start();
}
private void SocketListenLoop() {
while (m_open)
{
string text = m_sr.ReadLine();
OnTextReceived(text);
}
}
public void Disconnect() {
m_open = false;
// abort the thread but don't let the exception run amok
try { m_tdListener.Abort(); } catch {}
m_sr.Close();
m_sw.Close();
m_ns.Close(); // you'll need to create a new Socket and NetworkStream; might as well just dispose this entire object.
}
public void Send(string text) {
m_sw.WriteLine(text);
}
This assumes you're using a text-only protocol. For more complicated binary protocols, you'll need to access a byte stream. You can control your own buffer using the Socket directly (BeginReceive/EndReceive), or you can use a NetworkStream (BeginRead/EndRead). At the end of the day, it's just a matter of semantics. I have GPL code available here (http://cvs.sourceforge.net/viewcvs.py/jinxbot/Jinx/Jinx.Core/Net/ConnectionBase.cs?rev=1.1&view=markup) that does this; in fact, it is intended to be used in a way that you override this class and simply override OnDataReceived() and OnDataSent(), and that you provide your own Send() method but call OnDataSending() to actually send the data.
Thanks MyndFyre issue resovled!