Thread: ping program

  1. #1
    Registered User
    Join Date
    Jan 2003
    Posts
    88

    ping program

    hello.

    doing some raw sockets programming and having some fun...this stuff has some real potential!

    but,
    im having a strange bug in my ping program....
    Code:
    /*
     *    pinger.c 
     *    This is a ping imitation program 
     *    It will send an ICMP ECHO packet to the server of 
     *    your choice and listen for an ICMP REPLY packet
     *    Have fun!
     */
    #include <stdio.h>
    #include <stdlib.h>
    #include <sys/types.h>
    #include <sys/socket.h>
    #include <netinet/in.h>
    #include <arpa/inet.h>
    #include <netdb.h>
    #include <linux/ip.h>
    #include <linux/icmp.h>
    #include <string.h>
    #include <unistd.h>
    
    
    char dst_addr[15];
    char src_addr[15];
    
    unsigned short in_cksum(unsigned short *, int);
    void parse_argvs(char**, char*, char* );
    void usage();
    char* getip();
    
    int main(int argc, char* argv[])
    {
        struct iphdr* ip;
        struct iphdr* ip_reply;
        struct icmphdr* icmp;
        struct sockaddr_in connection;
        char* packet;
        char* buffer;
        int sockfd;
        int optval;
        int addrlen;
        
        if (getuid() != 0)
        {
    	fprintf(stderr, "%s: root privelidges needed\n", *(argv + 0));
    	exit(EXIT_FAILURE);
        }
    
        parse_argvs(argv, dst_addr, src_addr);
        printf("Source address: %s\n", src_addr);
        printf("Destination address: %s\n", dst_addr);
        
        /*
         * allocate all necessary memory
        */
        ip = malloc(sizeof(struct iphdr));
        ip_reply = malloc(sizeof(struct iphdr));
        icmp = malloc(sizeof(struct icmphdr));
        packet = malloc(sizeof(struct iphdr) + sizeof(struct icmphdr));
        buffer = malloc(sizeof(struct iphdr) + sizeof(struct icmphdr));
        /****************************************************************/
        
        ip = (struct iphdr*) packet;
        icmp = (struct icmphdr*) (packet + sizeof(struct iphdr));
        
        /*  
         *	here the ip packet is set up except checksum
         */
        ip->ihl			= 5;
        ip->version			= 4;
        ip->tos			= 0;
        ip->tot_len			= sizeof(struct iphdr) + sizeof(struct icmphdr);
        ip->id			= htons(random());
        ip->ttl			= 255;
        ip->protocol		= IPPROTO_ICMP;
        ip->saddr			= inet_addr(src_addr);
        ip->daddr			= inet_addr(dst_addr);
    
        
        if ((sockfd = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP)) == -1)
        {
    	perror("socket");
    	exit(EXIT_FAILURE);
        }
        
        /* 
         *	IP_HDRINCL must be set on the socket so that
         *	the kernel does not attempt to automatically add
         *	a default ip header to the packet
         */
        
        setsockopt(sockfd, IPPROTO_IP, IP_HDRINCL, &optval, sizeof(int));
        
        /*
         *	here the icmp packet is created
         *	also the ip checksum is generated
         */
        icmp->type			= ICMP_ECHO;
        icmp->code			= 0;
        icmp->un.echo.id		= 0;
        icmp->un.echo.sequence	= 0;
        icmp->checksum 		= 0;
        icmp-> checksum		= in_cksum((unsigned short *)icmp, sizeof(struct icmphdr));
        
        ip->check			= in_cksum((unsigned short *)ip, sizeof(struct iphdr));
        
        connection.sin_family = AF_INET;
        connection.sin_addr.s_addr = inet_addr(dst_addr);
        
        /*
         *	now the packet is sent
         */
        
        sendto(sockfd, packet, ip->tot_len, 0, (struct sockaddr *)&connection, sizeof(struct sockaddr));
        printf("Sent %d byte packet to %s\n", sizeof(packet), dst_addr);
        
        /*
         *	now we listen for responses
         */
        addrlen = sizeof(connection);
        if (recvfrom(sockfd, buffer, sizeof(struct iphdr) + sizeof(struct icmphdr), 0, (struct sockaddr *)&connection, &addrlen) == -1)
        {
    	perror("recv");
        }
        else
        {
    	printf("Received %d byte reply from %s:\n", sizeof(buffer), dst_addr);
            ip_reply = (struct iphdr*) buffer;
    	printf("ID: %d\n", ntohs(ip_reply->id));
    	printf("TTL: %d\n", ip_reply->ttl);
        }
        close(sockfd);
        return 0;
    }
    
    void parse_argvs(char** argv, char* dst, char* src)
    {
        int i;
        if(!(*(argv + 1))) 
        {
    	/* there are no options on the command line */
    	usage();
    	exit(EXIT_FAILURE);	
        }
        if (*(argv + 1) && (!(*(argv + 2)))) 
        {
    	/* 
    	 *   only one argument provided
    	 *   assume it is the destination server
    	 *   source address is local host
    	 */
    	strncpy(dst, *(argv + 1), 15);
    	strncpy(src, getip(), 15);
    	return;
        }
        else if ((*(argv + 1) && (*(argv + 2))))
        {
    	/* 
    	 *    both the destination and source address are defined
    	 *    for now only implemented is a source address and 
    	 *    destination address
    	 */
    	strncpy(dst, *(argv + 1), 15);
    	i = 2;
    	while(*(argv + i + 1))
    	{
    	    if (strncmp(*(argv + i), "-s", 2) == 0)
    	    {
    		strncpy(src, *(argv + i + 1), 15);
    		break;
    	    }
    	    i++;
    	}
    
        }
    }
    
    void usage()
    {
        fprintf(stderr, "\nUsage: pinger [destination] <-s [source]>\n");
        fprintf(stderr, "Destination must be provided\n");
        fprintf(stderr, "Source is optional\n\n");
    }
    
    char* getip()
    {
        char buffer[256];
        struct hostent* h;
        
        gethostname(buffer, 256);
        h = gethostbyname(buffer);
        
        return inet_ntoa(*(struct in_addr *)h->h_addr);
        
    }
    /*
     * in_cksum --
     * Checksum routine for Internet Protocol
     * family headers (C Version)
     */
    unsigned short in_cksum(unsigned short *addr, int len)
    {
        register int sum = 0;
        u_short answer = 0;
        register u_short *w = addr;
        register int nleft = len;
        /*
         * Our algorithm is simple, using a 32 bit accumulator (sum), we add
         * sequential 16 bit words to it, and at the end, fold back all the
         * carry bits from the top 16 bits into the lower 16 bits.
         */
        while (nleft > 1)
        {
    	  sum += *w++;
    	  nleft -= 2;
        }
        /* mop up an odd byte, if necessary */
        if (nleft == 1)
        {
    	  *(u_char *) (&answer) = *(u_char *) w;
    	  sum += answer;
        }
        /* add back carry outs from top 16 bits to low 16 bits */
        sum = (sum >> 16) + (sum & 0xffff);		/* add hi 16 to low 16 */
        sum += (sum >> 16);				/* add carry */
        answer = ~sum;				/* truncate to 16 bits */
        return (answer);
    }

    the code is pretty simple...it should make sense...


    say 192.168.0.5 is a machine on my network and 192.168.0.7 is my machine:

    if i do:
    ./pinger 192.168.0.5 -s 192.168.0.7
    it works! its great i even confirmed the ICMP REPLY packet with a sniffer (ethereal) and the ttl and the ID match....very sexy
    but if i do
    ./pinger 192.168.0.5
    (note that getip() does return 192.168.0.7) no reply is received....looking closer i found that the one with out source specified on the command line ends up sending only an ip packet with the fragment flags turned on! what the hell is that all about?

    thx for help
    Last edited by lithium; 07-08-2003 at 01:34 AM.

  2. #2
    Registered User
    Join Date
    Mar 2003
    Posts
    143
    First off I should warn you that I know nothing about sockets so this may not be the answer to your problem, but I did notice that you have some memory related problems that can often lead to strange behaviour.

    1) you do not free() any of the memory that you malloc().

    2) you malloc() memory pointed to by ip and ipcmp, then change the value of these pointers to point to some other memory locations. This leaves the previous memory hanging around with no way of using it or freeing it up. I suspect, given the rest of your code, that you do not need to malloc these two areas in the first place. You also do the same thing with ip_reply later in the code.

    3) sizeof(packet) will not give you the size of the packet you sent but the size of the pointer to char that packet is. I know that this has nothing to do with the code not working, but it's just a point to notice ...

    All these things may have no effect whatsoever on the curent problem you are seeing, but it is worth fixing them to avoid future problems, but one of them may have some strange side effect that causes your problems...

    Good luck
    DavT
    -----------------------------------------------

  3. #3
    Just because ygfperson's Avatar
    Join Date
    Jan 2002
    Posts
    2,490
    Look into your parse_argvs function. Theoretically, that should be the only difference between the two command lines you typed in.

  4. #4
    Registered User
    Join Date
    Jan 2003
    Posts
    88
    Originally posted by DavT
    First off I should warn you that I know nothing about sockets so this may not be the answer to your problem, but I did notice that you have some memory related problems that can often lead to strange behaviour.

    1) you do not free() any of the memory that you malloc().

    2) you malloc() memory pointed to by ip and ipcmp, then change the value of these pointers to point to some other memory locations. This leaves the previous memory hanging around with no way of using it or freeing it up. I suspect, given the rest of your code, that you do not need to malloc these two areas in the first place. You also do the same thing with ip_reply later in the code.

    3) sizeof(packet) will not give you the size of the packet you sent but the size of the pointer to char that packet is. I know that this has nothing to do with the code not working, but it's just a point to notice ...

    All these things may have no effect whatsoever on the curent problem you are seeing, but it is worth fixing them to avoid future problems, but one of them may have some strange side effect that causes your problems...

    Good luck
    2. you are right...i dont need to malloc ip and icmp because of these lines:
    Code:
    ip = (struct iphdr*) packet;
    icmp = (struct icmphdr*) (packet + sizeof(iphdr));
    this gives ip and icmp memory in the total packet (packet). icmp is 20 bytes after ip (sizeof(struct iphdr)); i think i got this straight.
    ip_reply is also given space so same applies.


    1.
    free(packet);
    free(buffer);


    3. ip->tot_len

    here is the new code:
    Code:
    /*
     *    pinger.c 
     *    This is a ping imitation program 
     *    It will send an ICMP ECHO packet to the server of 
     *    your choice and listen for an ICMP REPLY packet
     *    Have fun!
     */
    #include <stdio.h>
    #include <stdlib.h>
    #include <sys/types.h>
    #include <sys/socket.h>
    #include <netinet/in.h>
    #include <arpa/inet.h>
    #include <netdb.h>
    #include <linux/ip.h>
    #include <linux/icmp.h>
    #include <string.h>
    #include <unistd.h>
    
    
    char dst_addr[15];
    char src_addr[15];
    
    unsigned short in_cksum(unsigned short *, int);
    void parse_argvs(char**, char*, char* );
    void usage();
    char* getip();
    
    int main(int argc, char* argv[])
    {
        struct iphdr* ip;
        struct iphdr* ip_reply;
        struct icmphdr* icmp;
        struct sockaddr_in connection;
        char* packet;
        char* buffer;
        int sockfd;
        int optval;
        int addrlen;
        int siz;
        
        if (getuid() != 0)
        {
    	fprintf(stderr, "%s: root privelidges needed\n", *(argv + 0));
    	exit(EXIT_FAILURE);
        }
    
        parse_argvs(argv, dst_addr, src_addr);
        printf("Source address: %s\n", src_addr);
        printf("Destination address: %s\n", dst_addr);
        
        /*
         * allocate all necessary memory
        */
        packet = malloc(sizeof(struct iphdr) + sizeof(struct icmphdr));
        buffer = malloc(sizeof(struct iphdr) + sizeof(struct icmphdr));
        /****************************************************************/
        
        ip = (struct iphdr*) packet;
        icmp = (struct icmphdr*) (packet + sizeof(struct iphdr));
        
        /*  
         *	here the ip packet is set up except checksum
         */
        ip->ihl			= 5;
        ip->version			= 4;
        ip->tos			= 0;
        ip->tot_len			= sizeof(struct iphdr) + sizeof(struct icmphdr);
        ip->id			= htons(random());
        ip->ttl			= 255;
        ip->protocol		= IPPROTO_ICMP;
        ip->saddr			= inet_addr(src_addr);
        ip->daddr			= inet_addr(dst_addr);
    
        
        if ((sockfd = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP)) == -1)
        {
    	perror("socket");
    	exit(EXIT_FAILURE);
        }
        
        /* 
         *	IP_HDRINCL must be set on the socket so that
         *	the kernel does not attempt to automatically add
         *	a default ip header to the packet
         */
        
        setsockopt(sockfd, IPPROTO_IP, IP_HDRINCL, &optval, sizeof(int));
        
        /*
         *	here the icmp packet is created
         *	also the ip checksum is generated
         */
        icmp->type			= ICMP_ECHO;
        icmp->code			= 0;
        icmp->un.echo.id		= 0;
        icmp->un.echo.sequence	= 0;
        icmp->checksum 		= 0;
        icmp-> checksum		= in_cksum((unsigned short *)icmp, sizeof(struct icmphdr));
        
        ip->check			= in_cksum((unsigned short *)ip, sizeof(struct iphdr));
        
        connection.sin_family = AF_INET;
        connection.sin_addr.s_addr = inet_addr(dst_addr);
        
        /*
         *	now the packet is sent
         */
        
        sendto(sockfd, packet, ip->tot_len, 0, (struct sockaddr *)&connection, sizeof(struct sockaddr));
        printf("Sent %d byte packet to %s\n", ip->tot_len, dst_addr);
        
        /*
         *	now we listen for responses
         */
        addrlen = sizeof(connection);
        if (( siz = recvfrom(sockfd, buffer, sizeof(struct iphdr) + sizeof(struct icmphdr), 0, (struct sockaddr *)&connection, &addrlen)) == -1)
        {
    	perror("recv");
        }
        else
        {
    	printf("Received %d byte reply from %s:\n", siz , dst_addr);
            ip_reply = (struct iphdr*) buffer;
    	printf("ID: %d\n", ntohs(ip_reply->id));
    	printf("TTL: %d\n", ip_reply->ttl);
        }
    
        free(packet);
        free(buffer);
        close(sockfd);
        return 0;
    }
    
    
    void parse_argvs(char** argv, char* dst, char* src)
    {
        int i;
        if(!(*(argv + 1))) 
        {
    	/* there are no options on the command line */
    	usage();
    	exit(EXIT_FAILURE);	
        }
        if (*(argv + 1) && (!(*(argv + 2)))) 
        {
    	/* 
    	 *   only one argument provided
    	 *   assume it is the destination server
    	 *   source address is local host
    	 */
    	strncpy(dst, *(argv + 1), 15);
    	strncpy(src, getip(), 15);
    	return;
        }
        else if ((*(argv + 1) && (*(argv + 2))))
        {
    	/* 
    	 *    both the destination and source address are defined
    	 *    for now only implemented is a source address and 
    	 *    destination address
    	 */
    	strncpy(dst, *(argv + 1), 15);
    	i = 2;
    	while(*(argv + i + 1))
    	{
    	    if (strncmp(*(argv + i), "-s", 2) == 0)
    	    {
    		strncpy(src, *(argv + i + 1), 15);
    		break;
    	    }
    	    i++;
    	}
    
        }
    }
    
    void usage()
    {
        fprintf(stderr, "\nUsage: pinger [destination] <-s [source]>\n");
        fprintf(stderr, "Destination must be provided\n");
        fprintf(stderr, "Source is optional\n\n");
    }
    
    char* getip()
    {
        char buffer[256];
        struct hostent* h;
        
        gethostname(buffer, 256);
        h = gethostbyname(buffer);
        
        return inet_ntoa(*(struct in_addr *)h->h_addr);
        
    }
    /*
     * in_cksum --
     * Checksum routine for Internet Protocol
     * family headers (C Version)
     */
    unsigned short in_cksum(unsigned short *addr, int len)
    {
        register int sum = 0;
        u_short answer = 0;
        register u_short *w = addr;
        register int nleft = len;
        /*
         * Our algorithm is simple, using a 32 bit accumulator (sum), we add
         * sequential 16 bit words to it, and at the end, fold back all the
         * carry bits from the top 16 bits into the lower 16 bits.
         */
        while (nleft > 1)
        {
    	  sum += *w++;
    	  nleft -= 2;
        }
        /* mop up an odd byte, if necessary */
        if (nleft == 1)
        {
    	  *(u_char *) (&answer) = *(u_char *) w;
    	  sum += answer;
        }
        /* add back carry outs from top 16 bits to low 16 bits */
        sum = (sum >> 16) + (sum & 0xffff);		/* add hi 16 to low 16 */
        sum += (sum >> 16);				/* add carry */
        answer = ~sum;				/* truncate to 16 bits */
        return (answer);
    }
    thats a lot nicer....
    the packet is 28 bytes: confirmed by sniffer (without the ethernet header)

    still doesnt work:
    i printf src addr and dst addr with both commands and they are the same!



    strange.....

    thx

  5. #5
    Registered User
    Join Date
    Jan 2003
    Posts
    88
    is the getip() function ok?

  6. #6
    Registered User
    Join Date
    Jan 2003
    Posts
    88
    fixeded it:

    Code:
    /*
     *    pinger.c 
     *    This is a ping imitation program 
     *    It will send an ICMP ECHO packet to the server of 
     *    your choice and listen for an ICMP REPLY packet
     *    Have fun!
     */
    #include <stdio.h>
    #include <stdlib.h>
    #include <sys/types.h>
    #include <sys/socket.h>
    #include <netinet/in.h>
    #include <arpa/inet.h>
    #include <netdb.h>
    #include <linux/ip.h>
    #include <linux/icmp.h>
    #include <string.h>
    #include <unistd.h>
    
    
    char dst_addr[20];
    char src_addr[20];
    
    unsigned short in_cksum(unsigned short *, int);
    void parse_argvs(char**, char*, char* );
    void usage();
    char* getip();
    char* toip(char*);
    
    int main(int argc, char* argv[])
    {
        struct iphdr* ip;
        struct iphdr* ip_reply;
        struct icmphdr* icmp;
        struct sockaddr_in connection;
        char* packet;
        char* buffer;
        int sockfd;
        int optval;
        int addrlen;
        int siz;
    
        
        if (getuid() != 0)
        {
    	fprintf(stderr, "%s: root privelidges needed\n", *(argv + 0));
    	exit(EXIT_FAILURE);
        }
    
        parse_argvs(argv, dst_addr, src_addr);
        strncpy(dst_addr, toip(dst_addr), 20);
        strncpy(src_addr, toip(src_addr), 20);
        printf("Source address: %s\n", src_addr);
        printf("Destination address: %s\n", dst_addr);
        
        /*
         * allocate all necessary memory
        */
        packet = malloc(sizeof(struct iphdr) + sizeof(struct icmphdr));
        buffer = malloc(sizeof(struct iphdr) + sizeof(struct icmphdr));
        /****************************************************************/
        
        ip = (struct iphdr*) packet;
        icmp = (struct icmphdr*) (packet + sizeof(struct iphdr));
        
        /*  
         *	here the ip packet is set up
         */
    ip->ihl			= 5;
        ip->version			= 4;
        ip->tos			= 0;
        ip->tot_len			= sizeof(struct iphdr) + sizeof(struct icmphdr);
        ip->id			= htons(0);
        ip->frag_off		= 0;
        ip->ttl			= 64;
        ip->protocol		= IPPROTO_ICMP;
        ip->saddr			= inet_addr(src_addr);
        ip->daddr			= inet_addr(dst_addr);
        ip->check			= in_cksum((unsigned short *)ip, sizeof(struct iphdr));
        
        if ((sockfd = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP)) == -1)
        {
    	perror("socket");
    	exit(EXIT_FAILURE);
        }
        
        /* 
         *	IP_HDRINCL must be set on the socket so that
         *	the kernel does not attempt to automatically add
         *	a default ip header to the packet
         */
        
        setsockopt(sockfd, IPPROTO_IP, IP_HDRINCL, &optval, sizeof(int));
        
        /*
         *	here the icmp packet is created
         *	also the ip checksum is generated
         */
        icmp->type			= ICMP_ECHO;
        icmp->code			= 0;
        icmp->un.echo.id		= random();
        icmp->un.echo.sequence	= 0;
        icmp-> checksum		= in_cksum((unsigned short *)icmp, sizeof(struct icmphdr));
        
        
        connection.sin_family = AF_INET;
        connection.sin_addr.s_addr = inet_addr(dst_addr);
        
        /*
         *	now the packet is sent
         */
        
        sendto(sockfd, packet, ip->tot_len, 0, (struct sockaddr *)&connection, sizeof(struct sockaddr));
        printf("Sent %d byte packet to %s\n", ip->tot_len, dst_addr);
        
        /*
         *	now we listen for responses
         */
        addrlen = sizeof(connection);
        if (( siz = recvfrom(sockfd, buffer, sizeof(struct iphdr) + sizeof(struct icmphdr), 0, (struct sockaddr *)&connection, &addrlen)) == -1)
        {
    	perror("recv");
        }
        else
        {
    	printf("Received %d byte reply from %s:\n", siz , dst_addr);
            ip_reply = (struct iphdr*) buffer;
    	printf("ID: %d\n", ntohs(ip_reply->id));
    	printf("TTL: %d\n", ip_reply->ttl);
        }
    
        free(packet);
        free(buffer);
        close(sockfd);
        return 0;
    }
    void parse_argvs(char** argv, char* dst, char* src)
    {
        int i;
        if(!(*(argv + 1))) 
        {
    	/* there are no options on the command line */
    	usage();
    	exit(EXIT_FAILURE);	
        }
        if (*(argv + 1) && (!(*(argv + 2)))) 
        {
    	/* 
    	 *   only one argument provided
    	 *   assume it is the destination server
    	 *   source address is local host
    	 */
    	strncpy(dst, *(argv + 1), 15);
    	strncpy(src, getip(), 15);
    	return;
        }
        else if ((*(argv + 1) && (*(argv + 2))))
        {
    	/* 
    	 *    both the destination and source address are defined
    	 *    for now only implemented is a source address and 
    	 *    destination address
    	 */
    	strncpy(dst, *(argv + 1), 15);
    	i = 2;
    	while(*(argv + i + 1))
    	{
    	    if (strncmp(*(argv + i), "-s", 2) == 0)
    	    {
    		strncpy(src, *(argv + i + 1), 15);
    		break;
    	    }
    	    i++;
    	}
        }
    
    }
    
    void usage()
    {
        fprintf(stderr, "\nUsage: pinger [destination] <-s [source]>\n");
        fprintf(stderr, "Destination must be provided\n");
        fprintf(stderr, "Source is optional\n\n");
    }
    
    char* getip()
    {
        char buffer[256];
        struct hostent* h;
        
        gethostname(buffer, 256);
        h = gethostbyname(buffer);
        
        return inet_ntoa(*(struct in_addr *)h->h_addr);
        
    }
    
    /*
     * return the ip address if host provided by DNS name
     */
    char* toip(char* address)
    {
        struct hostent* h;
        h = gethostbyname(address);
        return inet_ntoa(*(struct in_addr *)h->h_addr);
    }
    
    /*
     * in_cksum --
     * Checksum routine for Internet Protocol
     * family headers (C Version)
     */
    unsigned short in_cksum(unsigned short *addr, int len)
    {
        register int sum = 0;
        u_short answer = 0;
        register u_short *w = addr;
        register int nleft = len;
        /*
         * Our algorithm is simple, using a 32 bit accumulator (sum), we add
         * sequential 16 bit words to it, and at the end, fold back all the
         * carry bits from the top 16 bits into the lower 16 bits.
         */
        while (nleft > 1)
        {
    	  sum += *w++;
    	  nleft -= 2;
        }
        /* mop up an odd byte, if necessary */
        if (nleft == 1)
        {
    	  *(u_char *) (&answer) = *(u_char *) w;
    	  sum += answer;
        }
        /* add back carry outs from top 16 bits to low 16 bits */
        sum = (sum >> 16) + (sum & 0xffff);		/* add hi 16 to low 16 */
        sum += (sum >> 16);				/* add carry */
        answer = ~sum;				/* truncate to 16 bits */
        return (answer);
    }
    what do you think? it works now
    also: it works for DNS addresses too!

    fun, fun, fun...

  7. #7
    Registered User
    Join Date
    Oct 2005
    Posts
    4

    Ethernet header

    If i want to change the ethernet header as also, how should I do?

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Using variables in system()
    By Afro in forum C Programming
    Replies: 8
    Last Post: 07-03-2007, 12:27 PM
  2. ping client
    By cpp_is_fun in forum C Programming
    Replies: 4
    Last Post: 11-29-2006, 12:44 PM
  3. BOOKKEEPING PROGRAM, need help!
    By yabud in forum C Programming
    Replies: 3
    Last Post: 11-16-2006, 11:17 PM
  4. My program, anyhelp
    By @licomb in forum C Programming
    Replies: 14
    Last Post: 08-14-2001, 10:04 PM