Thread: Need help coding a bouncer

  1. #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.

  2. #2
    and the Hat of Guessing tabstop's Avatar
    Join Date
    Nov 2007
    Posts
    14,336
    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.

  3. #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.

  4. #4
    Registered User
    Join Date
    Apr 2008
    Posts
    396
    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.

  5. #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.

  6. #6
    and the hat of int overfl Salem's Avatar
    Join Date
    Aug 2001
    Location
    The edge of the known universe
    Posts
    39,659
    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.
    If at first you don't succeed, try writing your phone number on the exam paper.

  7. #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 =)

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Replies: 9
    Last Post: 03-20-2009, 05:22 PM
  2. Coding Guideline ....!!
    By imfeelingfortun in forum Tech Board
    Replies: 8
    Last Post: 10-08-2006, 07:09 AM
  3. Before Coding
    By cyberCLoWn in forum C++ Programming
    Replies: 16
    Last Post: 12-15-2003, 02:26 AM
  4. Coding Contest....
    By Koshare in forum A Brief History of Cprogramming.com
    Replies: 46
    Last Post: 10-14-2001, 04:32 PM