C Board  

Go Back   C Board > General Programming Boards > Networking/Device Communication

Reply
 
LinkBack Thread Tools Display Modes
Old 01-02-2009, 11:34 AM   #1
Registered User
 
Join Date: Jan 2009
Posts: 10
Need help coding a bouncer

Hi, I'm trying to code an IRC proxy (aka bouncer), but I'm having troubles with it. I'm sorry for not being very specific, the problem in general is that it just doesn't work and I don't know where is the exact problem. I'm compiling in Ubuntu. Here is the code:

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

    #define MYPORT 3490

    #define BACKLOG 10
struct sockaddr_in server;

void *recibir(void *datos);

int socketirc(int sockirc, char *ip, int port);
    
typedef struct {
 int sockirc;
 int new_fd;
 } data;

void sigchld_handler(int s)
{
    while(wait(NULL) > 0);
}
void *recibir(void *datos) {
    data *misdatos = (data *) datos;
    char recvbuff[130];
    int result;
    fd_set readset;
    
    memset(&recvbuff, 0, sizeof(recvbuff));
    do {
        do {
            FD_ZERO(&readset);
            FD_SET(misdatos->sockirc, &readset);
            result = select(misdatos->sockirc + 1, &readset, NULL, NULL, NULL);
        } while (result == -1 && errno == EINTR);

    if (result > 0) {
        if (FD_ISSET(misdatos->sockirc, &readset)) {
       
            result = recv(misdatos->sockirc, recvbuff, sizeof(recvbuff), 0);
            if (result == 0) {
              
                close(misdatos->sockirc);
            }
            else {
                if (send(misdatos->new_fd, recvbuff, sizeof(recvbuff), 0) == -1)
                perror("send");
            }
       }
    }
    else if (result < 0) {
       
        printf("Error on select(): %s", strerror(errno));
    }
    } while(1);
}

int socketirc(int sockirc, char *ip, int port)
{
    if ((sockirc=socket(AF_INET, SOCK_STREAM, 0))==-1){
        return;
    }
         
    server.sin_addr.s_addr=inet_network(ip);
    server.sin_addr.s_addr=inet_addr(ip);
    server.sin_family = AF_INET; 
    server.sin_port = htons(port);
    bzero(&(server.sin_zero),8);

    if(connect(sockirc, (struct sockaddr *)&server, sizeof(struct sockaddr))==-1){
        exit(-1); 
    }
    else
        printf("funciona");
    return sockirc;
}
main(void)
{
    int sockfd, new_fd, sockirc, i, error;
    struct sockaddr_in my_addr;
    struct sockaddr_in their_addr;
    int sin_size, conectado = 0;
    struct sigaction sa;
    int yes=1, next = 0, port = 0;
    char recvbuff[130], *ptr, ip[15] = "vacio";
    struct hostent *h;
    data datos;
    pthread_t idHilo;

    if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
        perror("socket");
        exit(1);
    }

    if (setsockopt(sockfd,SOL_SOCKET,SO_REUSEADDR,&yes,sizeof(int)) == -1) {
        perror("setsockopt");
        exit(1);
    }
        
    my_addr.sin_family = AF_INET;
    my_addr.sin_port = htons(MYPORT);
    my_addr.sin_addr.s_addr = INADDR_ANY;
    memset(&(my_addr.sin_zero), '\0', 8);

    if (bind(sockfd, (struct sockaddr *)&my_addr, sizeof(struct sockaddr))
                                                                       == -1) {
        perror("bind");
        exit(1);
    }

    if (listen(sockfd, BACKLOG) == -1) {
        perror("listen");
        exit(1);
    }

    sa.sa_handler = sigchld_handler;
    sigemptyset(&sa.sa_mask);
    sa.sa_flags = SA_RESTART;
    if (sigaction(SIGCHLD, &sa, NULL) == -1) {
        perror("sigaction");
        exit(1);
    }

    while(1) {
        sin_size = sizeof(struct sockaddr_in);
        if ((new_fd = accept(sockfd, (struct sockaddr *)&their_addr, &sin_size)) == -1) {
            perror("accept");
            continue;
        }
        printf("server: got connection from %s\n", inet_ntoa(their_addr.sin_addr));
        if (!fork()) {
            close(sockfd);

            memset(&recvbuff, 0, sizeof(recvbuff));
            for(;;)
            {
                if(recv(new_fd, recvbuff, 128, 0))
                {
                    
                if (strstr(recvbuff, "irc") != NULL && strstr(ip, "vacio")) {
                    ptr = strtok(recvbuff, " ");
                    i = 1;
                    while(ptr != NULL ) {
                        if (next == 1) {
                            port = atoi(ptr);
                            sockirc = socketirc(sockirc, ip, port);
                            datos.sockirc = sockirc;
                            datos.new_fd = new_fd;
                            error = pthread_create (&idHilo, NULL, recibir, (void *) &datos);
                            next = 0;
                            break;
                        }
                        if (strstr(ptr, "irc") != NULL && strstr(ip, "vacio")) {
                            if ((h=gethostbyname(ptr)) == NULL) {
                                herror("gethostbyname");
                                exit(1);
                            }
                            h->h_addr = inet_ntoa(*(struct in_addr*)h->h_addr);
                            strcpy(ip, h->h_addr);
                            next = 1;
                        }
                        printf("%d\n", i);
                        i++;
                        printf("%s\n", ptr);
                        ptr = strtok(NULL, " ");
                    }
               }
                else {
                     if (send(sockirc, recvbuff, sizeof(recvbuff), 0) == -1)
                perror("send");
            }
                }
     

               
    }
                close(new_fd);
                exit(0);
            }
            close(new_fd);
        }

        return 0;
    }
I'd really appreciate if someone could check out the code and give me some advice.

Thanks in advance.
megareix is offline   Reply With Quote
Old 01-02-2009, 11:56 AM   #2
and the Hat of Guessing
 
tabstop's Avatar
 
Join Date: Nov 2007
Posts: 8,862
It is not possible to not be more specific than "it doesn't work". Presumably there is some way that it doesn't work, assuming it compiles; it must fail to connect, or fail to communicate, or fail in some other way.
tabstop is offline   Reply With Quote
Old 01-02-2009, 12:04 PM   #3
Registered User
 
Join Date: Jan 2009
Posts: 10
Yes, it compiles. And it can connect to the server. The problem comes then, when I try to join a channel or use any other command. To test it, configure the proxy server type in XChat as wingate. If you have any question, don't hesitate to ask.
megareix is offline   Reply With Quote
Old 01-03-2009, 03:28 AM   #4
Registered User
 
Join Date: Apr 2008
Posts: 282
Quote:
The problem comes then, when I try to join a channel or use any other command.
Yes? what happens then? try to add some printf() to help locating the problem, this is not a great solution but... I would rather advise to rework your whole code, split it in elementary functions, test them or at least add runtime check code, so you know precisely where it goes wrong. As a programmer, you cannot just say "it doesn't work, please help", you must be able to spot the problem, and then ask for help if you don't know how to solve it. You should try to use netcat for instance to check your proxy is able to receive something once it is connected.
root4 is offline   Reply With Quote
Old 01-04-2009, 01:31 AM   #5
Registered User
 
Join Date: Jan 2009
Posts: 10
Thanks for the answer root4. I tryed to use netcat as you said, and afer I send the irc server and the port (for example: irc.freenode.net 8001) I get this message over and over again, very fast: Error on select(): Bad file descriptorError on select()

And abou the recommendation of add printf(), I did, but I removed all of them to post the code here.
I'm completely clueless. I'd like to explain the pthread, because I think there can be any problem in the way I'm using it: I basically create the thread once I'm connected to the irc server, and I pass the socket of the server to de thread function (called recibir). So that function is in an infinite loop waiting to recive information from the irc server. Once it receives information, it pass that information to the client. Meanwhile, the main function waits until the client supplies information so it can pass it to the irc server.

I hope to be clear. I'm sorry I don't have a very specific question, but I have no clue about what's the specific problem. It would be very nice if someone takes the time to test it =)

Thanks in advance.
megareix is offline   Reply With Quote
Old 01-04-2009, 03:42 AM   #6
and the hat of Jobseeking
 
Salem's Avatar
 
Join Date: Aug 2001
Location: The edge of the known universe
Posts: 21,710
This is just some critique of one function. Some of the issues are elsewhere in the code as well.
Code:
//!! your datos pointer
//!! what is the scope of that data, does it go out of scope in the thread invoker?
//!! does it get re-used by the thread invoker
//!! does any data used here, get re-used (or say an fd closed) in the invoker?
void *recibir(void *datos) {
    data *misdatos = (data *) datos;
    char recvbuff[130];
    int result;
    fd_set readset;

    //!! 1. this does nothing useful.  Always use the return result of send() / recv()
    //!!    to determine the amount of valid data.
    //!! 2. the & on recvbuff is unnecessary
    memset(&recvbuff, 0, sizeof(recvbuff));
    do {
        do {
            FD_ZERO(&readset);
            FD_SET(misdatos->sockirc, &readset);
            result = select(misdatos->sockirc + 1, &readset, NULL, NULL, NULL);
        } while (result == -1 && errno == EINTR);

        if (result > 0) {
            if (FD_ISSET(misdatos->sockirc, &readset)) {
                result = recv(misdatos->sockirc, recvbuff, sizeof(recvbuff), 0);
                if (result == 0) {
                    close(misdatos->sockirc);
                    //!! again, get out of the loop, you're all done here
                }
                else {
                    //!! why sizeof(recvbuff), when you only have "result" bytes?
                    //!! don't assume that recv always fills the buffer
                    //!! Also, DON'T assume that send() sends everything on the first
                    //!! call, it doesn't.  You have to check how much was sent, and
                    //!! if necessary, call send() again with the tail of the unsent
                    //!! buffer (and a reduced length)
                    if (send(misdatos->new_fd, recvbuff, sizeof(recvbuff), 0) == -1)
                    perror("send");
                }
            }
        }
        else if (result < 0) {
            printf("Error on select(): %s", strerror(errno));
            //!! so why are you still in the loop if the connection has closed?
        }
    } while(1);
}
__________________
If you dance barefoot on the broken glass of undefined behaviour, you've got to expect the occasional cut.

Salem is offline   Reply With Quote
Old 01-05-2009, 07:33 PM   #7
Registered User
 
Join Date: Jan 2009
Posts: 10
Thanks a lot Salem, the problem is apparently because I send the whole recvbuff instead of "result" bytes. Apparently that was the problem, and now everything works perfect. Here is the new code:

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

    #define MYPORT 3490

    #define BACKLOG 10
struct sockaddr_in server;

void *recibir(void *datos);

int socketirc(int sockirc, char *ip, int port);
    
typedef struct {
 int sockirc;
 int new_fd;
 } data;

void sigchld_handler(int s)
{
    while(wait(NULL) > 0);
}
void *recibir(void *datos) {
    data *misdatos = (data *) datos;
    char recvbuff[130];
    int result = 0;
    fd_set readset;
    
    memset(&recvbuff, 0, sizeof(recvbuff));
    do {
        do {
            FD_ZERO(&readset);
            FD_SET(misdatos->sockirc, &readset);
            result = select(misdatos->sockirc + 1, &readset, NULL, NULL, NULL);
        } while (result == -1 && errno == EINTR);

    if (result > 0) {
        if (FD_ISSET(misdatos->sockirc, &readset)) {
       
            result = recv(misdatos->sockirc, recvbuff, 128, 0);
            if (result == 0) {
                close(misdatos->sockirc);
                break;
            }
            else {
                if (send(misdatos->new_fd, recvbuff, result, 0) == -1)
                perror("send");
            }
       }
    }
    else if (result < 0) {
        printf("Error on select(): %s", strerror(errno));
        break;
    }
    } while(1);
}

int socketirc(int sockirc, char *ip, int port)
{
    if ((sockirc=socket(AF_INET, SOCK_STREAM, 0))==-1){
        return;
    }
         
    server.sin_addr.s_addr=inet_network(ip);
    server.sin_addr.s_addr=inet_addr(ip);
    server.sin_family = AF_INET; 
    server.sin_port = htons(port);
    bzero(&(server.sin_zero),8);

    if(connect(sockirc, (struct sockaddr *)&server, sizeof(struct sockaddr))==-1){
        exit(-1); 
    }
    else
        printf("funciona");
    return sockirc;
}
main(void)
{
    int sockfd, new_fd, sockirc, i, error, result = 0;
    struct sockaddr_in my_addr;
    struct sockaddr_in their_addr;
    int sin_size, conectado = 0;
    struct sigaction sa;
    int yes=1, next = 0, port = 0;
    char recvbuff[130], *ptr, ip[15] = "vacio";
    struct hostent *h;
    data datos;
    pthread_t idHilo;

    if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
        perror("socket");
        exit(1);
    }

    if (setsockopt(sockfd,SOL_SOCKET,SO_REUSEADDR,&yes,sizeof(int)) == -1) {
        perror("setsockopt");
        exit(1);
    }
        
    my_addr.sin_family = AF_INET;
    my_addr.sin_port = htons(MYPORT);
    my_addr.sin_addr.s_addr = INADDR_ANY;
    memset(&(my_addr.sin_zero), '\0', 8);

    if (bind(sockfd, (struct sockaddr *)&my_addr, sizeof(struct sockaddr))
                                                                       == -1) {
        perror("bind");
        exit(1);
    }

    if (listen(sockfd, BACKLOG) == -1) {
        perror("listen");
        exit(1);
    }

    sa.sa_handler = sigchld_handler;
    sigemptyset(&sa.sa_mask);
    sa.sa_flags = SA_RESTART;
    if (sigaction(SIGCHLD, &sa, NULL) == -1) {
        perror("sigaction");
        exit(1);
    }

    while(1) {
        sin_size = sizeof(struct sockaddr_in);
        if ((new_fd = accept(sockfd, (struct sockaddr *)&their_addr, &sin_size)) == -1) {
            perror("accept");
            continue;
        }
        printf("server: got connection from %s\n", inet_ntoa(their_addr.sin_addr));
        if (!fork()) {
            close(sockfd);

            memset(&recvbuff, 0, sizeof(recvbuff));
            for(;;)
            {
                if((result = recv(new_fd, recvbuff, 128, 0)))
                {
                    
                if (strstr(recvbuff, "irc") != NULL && strstr(ip, "vacio")) {
                    ptr = strtok(recvbuff, " ");
                    i = 1;
                    while(ptr != NULL ) {
                        if (next == 1) {
                            port = atoi(ptr);
                            sockirc = socketirc(sockirc, ip, port);
                            datos.sockirc = sockirc;
                            datos.new_fd = new_fd;
                            error = pthread_create (&idHilo, NULL, recibir, (void *) &datos);
                            next = 0;
                            break;
                        }
                        if (strstr(ptr, "irc") != NULL && strstr(ip, "vacio")) {
                            if ((h=gethostbyname(ptr)) == NULL) {
                                herror("gethostbyname");
                                exit(1);
                            }
                            h->h_addr = inet_ntoa(*(struct in_addr*)h->h_addr);
                            strcpy(ip, h->h_addr);
                            next = 1;
                        }
                        printf("%d\n", i);
                        i++;
                        printf("%s\n", ptr);
                        ptr = strtok(NULL, " ");
                    }
               }
                else {
                     if (send(sockirc, recvbuff, result, 0) == -1)
                perror("send");
            }
                }
     

               
    }
                close(new_fd);
                exit(0);
            }
            close(new_fd);
        }

        return 0;
    }
I'm going to keep testing the code, but apparently everything work fine. If someone else has any recommendation for my code, don't hesitate to post it.

Again, thanks a lot Salem =)
megareix is offline   Reply With Quote
Reply

Thread Tools
Display Modes

Forum Jump

Similar Threads
Thread Thread Starter Forum Replies Last Post
The chicken and the egg problem... trying to learn coding but having trouble starting mothergoose729 Tech Board 9 03-20-2009 05:22 PM
Coding Guideline ....!! imfeelingfortun Tech Board 8 10-08-2006 07:09 AM
Before Coding cyberCLoWn C++ Programming 16 12-15-2003 02:26 AM
Coding Contest.... Koshare A Brief History of Cprogramming.com 46 10-14-2001 04:32 PM


All times are GMT -6. The time now is 05:20 AM.


Powered by vBulletin® Version 3.8.1
Copyright ©2000 - 2010, Jelsoft Enterprises Ltd.
Search Engine Optimization by vBSEO 3.3.2

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22