Become a MacRumors Supporter for $50/year with no ads, ability to filter front page stories, and private forums.

Soulstorm

macrumors 68000
Original poster
Feb 1, 2005
1,887
1
As you may remember from an older thread, I am diving into network connections, using the BSD sockets. My ultimate goal is to make a very basic IRC client.

However, I am stuck.

I have created a commend line tool in C and I have the following code:
Code:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <netdb.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <sys/socket.h>

#define PORT 6667 // the port client will be connecting to 

#define MAXDATASIZE 1000 // max number of bytes we can get at once 

int main(int argc, char *argv[])
{
    int sockfd, numbytes;  
    char buf[MAXDATASIZE];
    struct hostent *he;
    struct sockaddr_in their_addr; // connector's address information 
	
	he = gethostbyname("efnet.teleglobe.net");
	sockfd = socket(PF_INET, SOCK_STREAM, 0);
	if (sockfd < 0) {
		printf("error creating the socket\n");
	}
    their_addr.sin_family	= AF_INET;
	their_addr.sin_port		= htons(PORT);
	their_addr.sin_addr		= *((struct in_addr *)he->h_addr);
	memset(their_addr.sin_zero, '\0', sizeof their_addr.sin_zero);

	
	if (connect(sockfd, (struct sockaddr *)&their_addr,
				sizeof their_addr) == -1) {
        perror("connect\n");
        exit(1);
    }
	else
		printf("You got the connection to the server!\n");
	char p[] = "join #macfilez";
	send(sockfd, p, sizeof(p), 0);
	
	recv(sockfd, buf, sizeof(buf), 0);
	buf[numbytes] = '\0';
	printf("Received: %s",buf);
	close(sockfd);
	
    return 0;
}
The server I put was a server running on IRC's EFNet network. I was supposed to receive a message, from the server, right? Not only this doesn't happen, my program also crashes without showing anything! (the debugger comes up with no explanation).

Any ideas why? Actually, I must have made a newbie mistake due to my ignorance. Please enlighten me.
 

lee1210

macrumors 68040
Jan 10, 2005
3,182
3
Dallas, TX
Try this:
Code:
include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <netdb.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <sys/socket.h>

#define PORT 6667 // the port client will be connecting to

#define MAXDATASIZE 1000 // max number of bytes we can get at once

int main(int argc, char *argv[])
{
    int sockfd, numbytes;
    char buf[MAXDATASIZE];
    struct hostent *he;
    struct sockaddr_in their_addr; // connector's address information

    he = gethostbyname("efnet.teleglobe.net");
    sockfd = socket(PF_INET, SOCK_STREAM, 0);
    if (sockfd < 0) {
      printf("error creating the socket\n");
    }
    their_addr.sin_family       = AF_INET;
    their_addr.sin_port         = htons(PORT);
    their_addr.sin_addr         = *((struct in_addr *)he->h_addr);
    memset(their_addr.sin_zero, '\0', sizeof their_addr.sin_zero);


    if (connect(sockfd, (struct sockaddr *)&their_addr,
                        sizeof their_addr) == -1) {
      perror("connect\n");
      exit(1);
    } else {
      printf("You got the connection to the server!\n");
      char p[] = "join #macfilez";
      send(sockfd, p, size(p), 0);
      fprintf(stderr,"After send, entering recv loop\n");
      numbytes=0;
      while(numbytes == 0) {
        fprintf(stderr,"In recv loop\n");
        numbytes=recv(sockfd, buf, sizeof(buf)-1, 0); //-1 b/c you will null terminate
      }
      fprintf(stderr,"After recv loop, %d bytes read.\n",numbytes);
      buf[numbytes] = '\0';
      fprintf(stderr,"After null term, %d bytes read.\n",numbytes);
      printf("Received: %s",buf);
      fflush(stdout);
      close(sockfd);
   }

    return 0;
}

It's not "done", but a message is read from the server:
NOTICE AUTH :*** Processing connection to efnet.teleglobe.net

I'm not familiar with irc, but hopefully this will point you in the right direction.

Also:
http://www.macosxhints.com/article.php?story=2003110513201777

That might help for doing the identd the server is expecting.
 

yeroen

macrumors 6502a
Mar 8, 2007
944
2
Cambridge, MA
It's crashing because numbytes is never intialized or indeed set anywhere, so the expression buf[numbytes] = '\0'; on line 44 is an invalid memory access.

You can adapt the above poster's changes to put you back on path.
 

Soulstorm

macrumors 68000
Original poster
Feb 1, 2005
1,887
1
I managed to proceed a little further with your help, guys. I now have a little program that receives everything that a server says after trying to connect.

That's the source:
Code:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <netdb.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <sys/socket.h>

#define PORT 6667 // the port client will be connecting to 

#define MAXDATASIZE 2000 // max number of bytes we can get at once 

int main(int argc, char *argv[])
{
    int sockfd, numbytes;
    char buf[MAXDATASIZE];
    struct hostent *he;
    struct sockaddr_in their_addr; // connector's address information
	
    he = gethostbyname("efnet.teleglobe.net");
    sockfd = socket(PF_INET, SOCK_STREAM, 0);
    if (sockfd < 0) {
		printf("error creating the socket\n");
    }
    their_addr.sin_family       = AF_INET;
    their_addr.sin_port         = htons(PORT);
    their_addr.sin_addr         = *((struct in_addr *)he->h_addr);
    memset(their_addr.sin_zero, '\0', sizeof their_addr.sin_zero);
	
	
    if (connect(sockfd, (struct sockaddr *)&their_addr,
				sizeof their_addr) == -1) {
		perror("connect\n");
		exit(1);
    } 
	else {
		printf("You got the connection to the server!\n");
		
		fprintf(stderr,"After send, entering recv loop\n");
		numbytes = 1;
		while(numbytes != 0) {
			numbytes = 0;
			memset(buf, 0, sizeof(buf));
			//fprintf(stderr,"In recv loop\n");
			numbytes=recv(sockfd, buf, sizeof(buf)-1, 0); //-1 b/c you will null terminate
			buf[numbytes] = '\0';
			printf("Received: %s",buf);
		}
		
		char command[] = "ping";
		
		send(sockfd, command, sizeof(command), 0);
		
		numbytes = 1;
		while(numbytes != 0) {
			numbytes = 0;
			memset(buf, 0, sizeof(buf));
			//fprintf(stderr,"In recv loop\n");
			numbytes=recv(sockfd, buf, sizeof(buf)-1, 0); //-1 b/c you will null terminate
			buf[numbytes] = '\0';
			printf("Received: %s",buf);
		}
		
		//fprintf(stderr,"After recv loop, %d bytes read.\n",numbytes);
		//fprintf(stderr,"After null term, %d bytes read.\n",numbytes);
		
		fflush(stdout);
		close(sockfd);
	}
	return 0;
}

However, this is my result:

Code:
[Session started at 2008-03-03 23:17:59 +0200.]
You got the connection to the server!
After send, entering recv loop
Received: NOTICE AUTH :*** Processing connection to efnet.teleglobe.net
Received: NOTICE AUTH :*** Looking up your hostname...
NOTICE AUTH :*** Checking Ident
NOTICE AUTH :*** Found your hostname
Received: NOTICE AUTH :*** No Ident response
Received: ERROR :Closing Link: 127.0.0.1 (Connection timed out)
Received: Received:

The last lines are shown after I leave the program running for a while... so I have some questions:
  1. what do the last lines mean (about ident responce)
  2. why did the connection close by iself?
  3. What am I supposed to read in order to get this done (if not already covered into the IRC specification)
  4. some people tell me about telnet... What is this? I read the wikipedia article and I must admit I don't understand much...
 

Soulstorm

macrumors 68000
Original poster
Feb 1, 2005
1,887
1
Here is some information on Ident.

http://en.wikipedia.org/wiki/Ident

http://tools.ietf.org/html/rfc1413

Looks like the IRC server can't find out who you are (as in your computer). Have you firewalled port 113?

I am using airport express to connect to the internet, which means I am behind a router. But I have forwarded this port to no effect.

EDIT: I still have the same reason with identd. I thought I needed an identd server, and I downloaded this one. But to no effect.
 

neoserver

macrumors 6502
Apr 24, 2003
335
0
I don't know much about the IRC protocol, but perhaps the server is closing the connection since you aren't sending anything to it? Don't most IRC servers have a PNG/QNG (ping/pong) challenge system to see if you're still there?
 

lee1210

macrumors 68040
Jan 10, 2005
3,182
3
Dallas, TX
[*]what do the last lines mean (about ident responce)
[*]why did the connection close by iself?
[*]What am I supposed to read in order to get this done (if not already covered into the IRC specification)
[*]some people tell me about telnet... What is this? I read the wikipedia article and I must admit I don't understand much...
[/LIST]

The last lines mean the server is rejecting the connection because it can't identify you (the identd issue).

The connection closed because the server terminated it when it was unable to identify you.

Other posters have pointed to sources of ident information, this is what I would look at next. This leads into your last question, you can try:
telnet localhost 113
from the terminal and see if you get a reply. if you do, and you do have your router forwarding TCP port 113 to the IP of your machine, the remote server should be OK with getting your ident that way.

The other use for telnet in this case is to evaluate what the server will send, test your responses, etc.

You can run:
telnet efnet.teleglobe.net 6667
And this will open a connection to the server you are trying to connect to with your program. From here you can enter commands and see what the server's response is. this gives you an easy means of validating what you need to listen for in your program and what the appropriate replies are without constantly modifying your program.

Take a look at ident and see if you can get that going first. That seems to be the primary stumbling block right now.

-Lee
 

x704

macrumors regular
Apr 15, 2006
118
0
I had the same problem... after you connect, you then need to send two thing to the server...

NICK MyWayCoolBotNick\r\n
USER ObjcBot 8 * :The Objective-C Bot\r\n

Or something like that... as I recall thats where the server stopped caring about my connection and terminated me. the next thing you would need to do is reply to ping messages, otherwise the server will get mad at you:

PONG insertServerHere\r\n

Don't forget to join a channel!

JOIN #macdev\r\n
 

Soulstorm

macrumors 68000
Original poster
Feb 1, 2005
1,887
1
I had the same problem... after you connect, you then need to send two thing to the server...



Or something like that... as I recall thats where the server stopped caring about my connection and terminated me. the next thing you would need to do is reply to ping messages, otherwise the server will get mad at you:

Don't forget to join a channel!

Thanks a lot! That seemed to have fixed the problem! I connected using the terminal! Now all I have to do is the rest (build the program).

lee1210, thanks a lot. i ran the command you gave me into the terminal, and then it worked. However, the ident could not be resolved.
 

Soulstorm

macrumors 68000
Original poster
Feb 1, 2005
1,887
1
I had the same problem... after you connect, you then need to send two thing to the server...



Or something like that... as I recall thats where the server stopped caring about my connection and terminated me. the next thing you would need to do is reply to ping messages, otherwise the server will get mad at you:



Don't forget to join a channel!


OK, I managed to do this using the terminal, but there is still something I miss.

With the command "telnet efnet.teleglobe.net 6667" I get to open a telnet communication with the server. The same thing happens when I use the connect() function in C++. But afterwards, how can I send those 2 commands I need (NICK and USER) using C++? In the terminal, typing

Code:
NICK MyWayCoolBotNick\r\n
USER ObjcBot 8 * :The Objective-C Bot\r\n
is sufficient. But in C++, I try to use the send() command but with no effect. What am I doing wrong?

Code:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <netdb.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <sys/socket.h>

#define PORT 6667 // the port client will be connecting to 

#define MAXDATASIZE 2000 // max number of bytes we can get at once 

int main(int argc, char *argv[])
{
	int sockfd, numbytes;
    char buf[MAXDATASIZE];
    struct hostent *he;
    struct sockaddr_in their_addr; // connector's address information
	
    he = gethostbyname("efnet.teleglobe.net");
    sockfd = socket(PF_INET, SOCK_STREAM, 0);
    if (sockfd < 0) {
		printf("error creating the socket\n");
    }
    their_addr.sin_family       = AF_INET;
    their_addr.sin_port         = htons(PORT);
    their_addr.sin_addr         = *((struct in_addr *)he->h_addr);
    memset(their_addr.sin_zero, '\0', sizeof their_addr.sin_zero);
	
	
    if (connect(sockfd, (struct sockaddr *)&their_addr,
				sizeof their_addr) == -1) {
		perror("connect\n");
		exit(1);
    } 
	else {
		printf("You got the connection to the server!\n");
		
		fprintf(stderr,"After send, entering recv loop\n");
		numbytes = 0;
		do {
			numbytes = 0;
			memset(buf, 0, sizeof(buf));
			//fprintf(stderr,"In recv loop\n");
			numbytes=recv(sockfd, buf, sizeof(buf)-1, 0); //-1 b/c you will null terminate
			buf[numbytes] = '\0';
			printf("Received: %s",buf);
		} while (numbytes != 0);
		
		//char command[] = "PING\r\n";
		char nickCommand[] = "NICK MyWayCoolBotNick\r\n";
		char userCommand[] = "USER ObjcBot 8 * :The Objective-C Bot\r\n";
		//system("telnet efnet.teleglobe.net 6667");
		
		//send(sockfd, command, sizeof(command), 0);
		send(sockfd, nickCommand, sizeof(nickCommand), 0);
		send(sockfd, userCommand, sizeof(userCommand), 0);
		
		printf("exited first loop!!!\n");
		do {
			
			numbytes = 0;
			memset(buf, 0, sizeof(buf));
			//fprintf(stderr,"In recv loop\n");
			numbytes=recv(sockfd, buf, sizeof(buf)-1, 0); //-1 b/c you will null terminate
			buf[numbytes] = '\0';
			printf("Received: %s",buf);
		} while (numbytes !=0);
		
		
		
		fflush(stdout);
		close(sockfd);
	}
	return 0;
}
 

pilotError

macrumors 68020
Apr 12, 2006
2,237
4
Long Island
Do you get anything back on the line or are you just getting terminated?

You can also try doing a tcpdump to see if your actually sending the data and see if there's something that your not picking up.

I doubt this is an issue, but you could also trying turning on tcp nodelay on the socket level.
 

Soulstorm

macrumors 68000
Original poster
Feb 1, 2005
1,887
1
Do you get anything back on the line or are you just getting terminated?

You can also try doing a tcpdump to see if your actually sending the data and see if there's something that your not picking up.

I doubt this is an issue, but you could also trying turning on tcp nodelay on the socket level.

I don't know how to use tcpdump and I don't understand the man pages.

And I am just getting terminated. This is my output log:
Code:
christos-sotirious-imac:~ soulstorm$ /Users/soulstorm/CoreFoundation\ tool/build/Release/CoreFoundation\ tool ; exit;
You got the connection to the server!
After send, entering recv loop
Received: NOTICE AUTH :*** Processing connection to efnet.teleglobe.net
Received: NOTICE AUTH :*** Looking up your hostname...
NOTICE AUTH :*** Checking Ident
NOTICE AUTH :*** Found your hostname
Received: NOTICE AUTH :*** No Ident response
********************time passes ******************
Received: ERROR :Closing Link: 127.0.0.1 (Connection timed out)
Received: exited first loop!!!
Received: logout
[Process completed]

Just this. How can I verify what I am sending using tcpdump?
 

lee1210

macrumors 68040
Jan 10, 2005
3,182
3
Dallas, TX
I don't know how to use tcpdump and I don't understand the man pages.

And I am just getting terminated. This is my output log:
<clip>
Just this. How can I verify what I am sending using tcpdump?

I would move the two send statements with the nick and user BEFORE the first input loop.

I realize that I lead you astray on this point with the reading until numbytes is 0, because I wasn't totally sure what the protocol was like. Essentially you'll stay in that loop until the server disconnects you and there is nothing left to read (I believe).

If you send nick and user first, what you get back from the server should be a welcome message, etc. Afterwards you should be able to send your join command.

This is where experimenting with telnet should come in handy, because you can see what to send to the server and when, and what its responses will be.

I can't comment too much on tcpdump, but if you were to use it you would likely only want to listen to connections to the efnet server on the port you are using, so you only see the tcp activity from your program. If you don't have a filter like this you will probably have a very hard time viewing the output because it will be full of other tcp communications to and from your computer.

-Lee
 

Soulstorm

macrumors 68000
Original poster
Feb 1, 2005
1,887
1
that worked, thanks a lot.

Code:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <netdb.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <sys/socket.h>

#define PORT 6667 // the port client will be connecting to 

#define MAXDATASIZE 2000 // max number of bytes we can get at once 
char nickCommand[] = "NICK MyWayCoolBotNick\r\n";
char userCommand[] = "USER ObjcBot 8 * :The Objective-C Bot\r\n";

char allCommands[] = "NICK MyWayCoolBotNick\r\nUSER ObjcBot 8 * :The Objective-C Bot\r\n";

int main(int argc, char *argv[])
{
	int sockfd, numbytes;
    char buf[MAXDATASIZE];
    struct hostent *he;
    struct sockaddr_in their_addr; // connector's address information
	
    he = gethostbyname("efnet.teleglobe.net");
    sockfd = socket(PF_INET, SOCK_STREAM, 0);
    if (sockfd < 0) {
		printf("error creating the socket\n");
    }
    their_addr.sin_family       = AF_INET;
    their_addr.sin_port         = htons(PORT);
    their_addr.sin_addr         = *((struct in_addr *)he->h_addr);
    memset(their_addr.sin_zero, '\0', sizeof their_addr.sin_zero);
	
	
    if (connect(sockfd, (struct sockaddr *)&their_addr,
				sizeof their_addr) == -1) {
		perror("connect\n");
		exit(1);
    }
	else {
		//send(sockfd, nickCommand, sizeof(nickCommand), 0);
		//send(sockfd, userCommand, sizeof(userCommand), 0);
		send(sockfd, allCommands, sizeof(allCommands), 0);
		printf("You got the connection to the server!\n");
		
		fprintf(stderr,"After send, entering recv loop\n");
		numbytes = 0;
		
		
		do {
			numbytes = 0;
			memset(buf, 0, sizeof(buf));
			//fprintf(stderr,"In recv loop\n");
			numbytes=recv(sockfd, buf, sizeof(buf)-1, 0); //-1 b/c you will null terminate
			buf[numbytes] = '\0';
			printf("Received: %s",buf);
		} while (numbytes != 0);
		
		//char command[] = "PING\r\n";
		
		//system("telnet efnet.teleglobe.net 6667");
		
		//send(sockfd, command, sizeof(command), 0);
		
		printf("exited first loop!!!\n");
		do {
			
			numbytes = 0;
			memset(buf, 0, sizeof(buf));
			//fprintf(stderr,"In recv loop\n");
			numbytes=recv(sockfd, buf, sizeof(buf)-1, 0); //-1 b/c you will null terminate
			buf[numbytes] = '\0';
			printf("Received: %s",buf);
		} while (numbytes !=0);
		
		
		
		fflush(stdout);
		close(sockfd);
	}
	return 0;
}

I noticed something strange, though. If I send the commands about the NICK and USER, I will get nothing. Else, I get the correct result (the correct response from the server). Why does this happen? I mean, is it not the same?
 
Register on MacRumors! This sidebar will go away, and you'll see fewer ads.