source: trunk/instant_messenger/socket/server.c @ 151

Revision 151, 16.3 KB checked in by niltonneto, 16 years ago (diff)

Commit da nova versão do módulo, usando agente em C.
Vide Página do módulo do Trac:
http://www.expressolivre.org/dev/wiki/messenger

A versão anterior encontra-se na subpasta bkp (32/64).

Line 
1#include "server.h"
2
3struct accept
4{
5        int newfd;
6        struct sockaddr_in sa;
7        struct in_addr jabber_addr;
8        unsigned short jabber_port;
9};
10
11struct client
12{
13        char * user;
14        int client_fd;
15        int jabber_fd;
16        int keep_alive;
17        time_t last_action;
18        struct client * next;
19        struct client * previous;
20};
21
22struct cat
23{
24        int in_fd,
25                out_fd;
26        int jabber,
27                keep_alive;
28        struct client * client;
29};
30
31struct client * clients = (struct client *)NULL;
32
33pthread_mutex_t mutexsum;
34
35int main (int argc, char ** argv)
36{
37        struct in_addr remote_addr,
38                                   local_addr;
39        unsigned short remote_port,
40                                   local_port;
41        int listen_fd;
42
43        ParseArgs (argc, argv, &remote_addr, &remote_port, &local_addr, &local_port);
44
45        Initialise ();
46
47        // Create server socket before becoming a daemon so
48        // there is still a chance to print an error message.
49        listen_fd = CreateServerSocket (local_addr, local_port);
50        if ( listen_fd < 0 )
51                pbomb ("Unable to create server socket");
52
53        //Daemonise ();
54
55        MainLoop (listen_fd, remote_addr, remote_port); // never returns
56
57        syslog (LOG_ERR, "fim MainLoop(): %m");
58        exit (EXIT_SUCCESS);
59}
60
61// ParseArgs()
62// Parse the command line arguments to extract the remote
63// and local adresses and port numbers, ra, rp, la & lp.
64// Exit the program gracefully upon error.
65void ParseArgs (int argc, char ** argv, struct in_addr * ra, unsigned short * rp, struct in_addr * la, unsigned short * lp)
66{
67        // argv[0] = program name
68        // argv[1] = remote_addr
69        // argv[2] = remote_port
70        // argv[3] = local_addr (optional)
71        // argv[4] = local_port (optional)
72
73        char * p = strrchr (argv[0], '/');
74
75        strncpy (g_program_name, (p == NULL) ? argv[0] : p + 1, sizeof (g_program_name) - 1);
76
77        if ( (argc < 3) || (argc > 5) )
78        {
79                fprintf (stderr, "usage: %s remote_addr remote_port [local_addr] [local_port]\n", argv[0]);
80                exit (EXIT_FAILURE);
81        }
82
83        if ( NameToAddr (argv[1], ra) )
84                hbomb ("Unable to resolve \"%s\" to an ip address", argv[1]);
85
86        if ( NameToPort (argv[2], rp, "tcp") )
87                quit ("Unable to resolve \"%s\" to a port number", argv[2]);
88
89        if ( argc < 4 )
90                la->s_addr = htonl (INADDR_ANY);
91        else
92                if ( NameToAddr (argv[3], la) )
93                        hbomb ("Unable to resolve \"%s\" to an ip address", argv[3]);
94
95        if ( argc < 5 )
96                memcpy (lp, rp, sizeof (*lp));
97        else
98                if ( NameToPort (argv[4], lp, "tcp") )
99                        quit ("Unable to resolve \"%s\" to a port number", argv[4]);
100}
101
102// Initialise()
103// Setup syslog, signal handlers, and other intialisation.
104void Initialise (void)
105{
106        openlog (g_program_name, LOG_PID, LOG_USER);
107        syslog (LOG_INFO, "%s started", g_program_name);
108
109        chdir ("/"); // Change working directory to the root.
110
111        umask (0); // Clear our file mode creation mask
112
113        //set_signal_handler (SIGCHLD, sig_child);
114
115        //signal (SIGPIPE, SIG_IGN);
116}
117
118// CreateServerSocket()
119// Create a socket, bind it to the specified address
120// and port, and set it to listen for client connections.
121// Returns < 0 on failure to bind, bombs on error otherwise,
122// returns the fd of the new socket on success.
123int CreateServerSocket (struct in_addr addr, unsigned short port)
124{
125        int err,
126                fd;
127        const int on = 1;
128        struct sockaddr_in sa;
129
130        // Create a socket and get its descriptor.
131        fd = socket (AF_INET, SOCK_STREAM, 0);
132        if ( fd < 0 )
133                syslog (LOG_ERR, "socket(): %m"), exit (EXIT_FAILURE);
134
135        // Set SO_REUSEADDR socket option
136        if ( setsockopt (fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof (on)) < 0 )
137                syslog (LOG_ERR, "setsockopt(fd%d, SO_REUSEADDR): %m", fd);
138
139        // Load a sa structure with the specified address and port
140        sa.sin_family = AF_INET;
141        sa.sin_port = htons (port);
142        //sa.sin_addr = addr;
143        sa.sin_addr.s_addr = htonl(INADDR_ANY);
144        memset (sa.sin_zero, 0, sizeof (sa.sin_zero));
145
146        // Bind our socket to the address and port specified
147        err = bind (fd, (struct sockaddr *) &sa, sizeof (sa));
148        if ( err < 0 )
149        {
150                syslog (LOG_ERR, "bind(): %m");
151                return err;
152        }
153
154        // Tell socket to listen and queue up to 5 incoming connections.
155        if ( listen (fd, 5) < 0 )
156                syslog (LOG_ERR, "listen(): %m"), exit (EXIT_FAILURE);
157
158        return fd;
159}
160
161// MainLoop()
162// Classic concurrent server model.
163// Wait for a client to connect, fork a child process
164// to do the business with the client, parent process
165// continues to wait for the next connection.
166// This function does not return.
167void MainLoop (int listen_fd, struct in_addr rem_addr, unsigned short rem_port)
168{
169        struct accept * accept;
170        pthread_t accept_thread,
171                          clear_list_thread;
172
173        pthread_mutex_init(&mutexsum, NULL);
174
175        pthread_create(&clear_list_thread, NULL, (void *) &ClearList, (void *)NULL );
176
177        for ( ; ; )
178        {
179                accept = AcceptClientConnection (listen_fd);
180                accept->jabber_addr = rem_addr;
181                accept->jabber_port = rem_port;
182
183                pthread_create(&accept_thread, NULL, (void *) &VerifyClient, (void *) accept);
184        }
185        pthread_mutex_destroy(&mutexsum);
186        pthread_exit(NULL);
187}
188
189void ClearList(void)
190{
191        struct client * current,
192                                  * client_remove;
193
194        for ( ; ; )
195        {
196                current = clients;
197                pthread_mutex_lock(&mutexsum);
198                while ( current != (struct client *)NULL )
199                {
200                        //printf("client: %s....\n", current->user);
201                        if ( time(NULL) - current->last_action > 60 )
202                        {
203                                //puts("\t#1 morto!");
204                                shutdown(current->jabber_fd, SHUT_RDWR);
205                                close(current->jabber_fd);
206                                current->jabber_fd = (int)NULL;
207                                //if ( current->previous == (struct client *)NULL )
208                                //{
209                                //puts("\t#2 morto!");
210                                        //if ( current->next != (struct client *)NULL )
211                                        //      current->next->previous = (struct client *)NULL;
212                                        //clients = current->next;
213                                //puts("\t#3 morto!");
214                                //}
215                                /*if ( current->previous != (struct client *)NULL )
216                                {
217                                        current->previous->next = current->next;
218                                        current->next->previous = current->previous;
219                                }
220                                else
221                                {
222                                        current->next->previous = (struct client *)NULL;
223                                }*/
224                                //puts("\t#4 morto!");
225                                //client_remove = current;
226                                current = current->next;
227                                //free(client_remove);
228                                //puts("\t#5 morto!");
229                        }
230                        else
231                                current = current->next;
232                }
233                //puts("-------------------------------");
234                pthread_mutex_unlock(&mutexsum);
235                sleep(2);
236        }
237}
238
239// AcceptClientConnection()
240// waits for a tcp connect to the socket listen_fd, which
241// must already be bound and set to listen on a local port.
242// Bombs on error, returns the fd of the new socket on success.
243struct accept * AcceptClientConnection (int listen_fd)
244{
245        int newfd;
246        struct sockaddr_in sa;
247        socklen_t socklen;
248
249        syslog (LOG_INFO, "AcceptClientConnection(fd%d)", listen_fd);
250
251        // Accept the connection and create a new socket for it.
252        socklen = sizeof (sa);
253        memset (&sa, 0, socklen);
254        do
255        {
256                newfd = accept (listen_fd, (struct sockaddr *) &sa, &socklen);
257        }
258        while ( (newfd < 0) && (errno == EINTR) );
259
260        syslog (LOG_INFO, "Accepted client connection on new socket fd%d", newfd);
261
262        if ( newfd < 0 )
263                syslog (LOG_ERR, "accept(): %m"), pthread_exit(0);
264
265        if ( socklen != sizeof (sa) )
266                syslog (LOG_ERR, "accept() screwed up!"), pthread_exit(0);
267
268        struct accept * new_accept = (struct accept *) malloc(sizeof(struct accept));
269        new_accept->newfd = newfd;
270        new_accept->sa = sa;
271
272        return (new_accept);
273}
274
275void VerifyClient(void * accept)
276{
277        int jabber_fd = (int)NULL;
278        struct accept * client = (struct accept *) accept;
279        struct client * user = (struct client *)NULL;
280        struct cat * info;
281        pthread_t cat_thread;
282
283        unsigned int addr = 0;
284        char buf[250];
285        addr = ntohl(client->sa.sin_addr.s_addr);
286        sprintf(buf,"%d.%d.%d.%d",
287                        (addr >> 24)  , (addr >> 16) & 0xFF ,
288                        (addr >> 8) & 0xFF ,  addr & 0xFF);
289        printf("New connection: %s\n\n", buf);
290
291        if ( strcmp(buf, "10.15.20.42") == 0 || strcmp(buf, "10.15.20.202") == 0 )
292        {
293                user = Handshake(client->newfd);
294                jabber_fd = user->jabber_fd;
295        }
296
297        if ( jabber_fd == (int)NULL )
298        {
299                jabber_fd = ConnectToServer(client->jabber_addr, client->jabber_port);
300
301                if ( user != (struct client *)NULL )
302                        user->jabber_fd = jabber_fd;
303        }
304
305        info = (struct cat *) malloc(sizeof(struct cat));
306
307        info->out_fd = jabber_fd;
308        info->in_fd = client->newfd;
309        info->jabber = (int)NULL;
310        info->keep_alive = (int)NULL;
311        info->client = user;
312
313        pthread_create(&cat_thread, NULL, (void *) &Cat, (void *)info );
314
315        pthread_exit(0);
316}
317
318struct client * Handshake(int newfd)
319{
320        float is_new_client;// = (float) NULL;
321        int bytes_rcvd,
322                bytes_sent,
323                i;
324
325        unsigned char * const buf = (char *) malloc (sizeof(char) * 5);
326        char * user = (char *) malloc(128 * sizeof(char)),
327                 * pass = (char *) malloc(128 * sizeof(char));
328
329        //struct client * clients = (struct client *)NULL;
330        struct client * new_client = (struct client *)NULL;
331
332        bzero(buf, 5);
333        sprintf(buf, "user");
334        for ( i = 0; i < sizeof(buf); i += bytes_sent )
335        {
336                bytes_sent = send (newfd, buf + i, sizeof(buf) - i, 0);
337
338                if ( bytes_sent < 0 )
339                        break;
340        }
341
342        bzero(user, 128);
343        if ( (bytes_rcvd = recv (newfd, user, 128, 0)) < 1 )
344                pthread_exit(0);
345
346        bzero(buf, 5);
347        sprintf(buf, "pass");
348        for ( i = 0; i < sizeof(buf); i += bytes_sent )
349        {
350                bytes_sent = send (newfd, buf + i, sizeof(buf) - i, 0);
351
352                if ( bytes_sent < 0 )
353                        break;
354        }
355
356        bzero(pass, 128);
357        if ( (bytes_rcvd = recv (newfd, pass, 128, 0)) < 1 )
358                pthread_exit(0);
359
360        pthread_mutex_lock (&mutexsum);
361        if ( clients == (struct client *)NULL )
362        {
363                clients = (struct client *) malloc(sizeof(struct client));
364
365                new_client = clients;
366                new_client->previous = (struct client *)NULL;
367                is_new_client = 1;
368        }
369        else
370        {
371                new_client = clients;
372                while ( ((is_new_client = (float)strcmp(new_client->user, user)) != 0) && (new_client->next != (struct client *)NULL) )
373                        new_client = new_client->next;
374
375                if ( is_new_client != 0 )
376                {
377                        new_client->next = (struct client *) malloc(sizeof(struct client));
378                        new_client->next->previous = new_client;
379                        new_client = new_client->next;
380                }
381        }
382
383        if ( is_new_client != 0 )
384        {
385                new_client->user = user;
386                new_client->jabber_fd = (int)NULL;
387                new_client->keep_alive = 1;
388                new_client->next = (struct client *)NULL;
389        }
390
391        bzero(buf, 5);
392        if ( is_new_client != 0 || new_client->jabber_fd == (int)NULL  )
393                sprintf(buf, "new");
394        else
395                sprintf(buf, "rec");
396
397        send (newfd, buf, 3, 0);
398
399        new_client->client_fd = newfd;
400        new_client->last_action = time(NULL);
401        pthread_mutex_unlock(&mutexsum);
402
403        return new_client;
404}
405
406// ConnectToServer()
407// attempts a tcp connect to the server specified
408// by addr and port.  Bombs on failure to connect,
409// returns the fd of the new socket on success.
410int ConnectToServer (struct in_addr addr, unsigned short port)
411{
412        // TODO: have a timeout for connect() - see Unix socket FAQ 6.2
413
414        int fd, err;
415        struct sockaddr_in sa;
416
417        // Create a socket and get its descriptor.
418        fd = socket (AF_INET, SOCK_STREAM, 0);
419
420        if ( fd < 0 )
421                syslog (LOG_ERR, "socket(): %m"), pthread_exit(0);//exit (EXIT_FAILURE);
422
423        sa.sin_family = AF_INET;
424        sa.sin_port = htons (port);
425        sa.sin_addr = addr;
426        memset (sa.sin_zero, 0, sizeof (sa.sin_zero));
427
428        err = connect (fd, (struct sockaddr *) &sa, sizeof (sa));
429        if (err < 0)
430        {
431                syslog (LOG_ERR, "Unable to connect socket fd%d to server: %m", fd);
432                //exit (EXIT_FAILURE);
433                pthread_exit(0);
434        }
435
436        syslog (LOG_INFO, "Connected socket fd%d to server", fd);
437
438        return fd;
439}
440
441// Cat()
442// read data from in_fd and write it to out_fd until
443// the connection is closed by one of the peers.
444// Data is copied using a dynamically allocated buffer.
445//void Cat (int in_fd, int out_fd)
446//void Cat (int in_fd, int out_fd)
447void Cat (void * info)
448{
449        unsigned char * const buf_in = (char *) malloc (sizeof(char) * BUF_SIZE);
450        unsigned char * const buf_out = (char *) malloc (sizeof(char) * BUF_SIZE);
451        int bytes_rcvd_in = (int) NULL,
452                bytes_sent_in = (int) NULL,
453                bytes_rcvd_out = (int) NULL,
454                bytes_sent_out = (int) NULL,
455                i,
456                in_fd,
457                out_fd;
458        struct cat * user = (struct cat *) info;
459        in_fd = user->in_fd;
460        out_fd = user->out_fd;
461
462        syslog (LOG_INFO, "Cat(fd%d, fd%d)", in_fd, out_fd);
463
464        if ( buf_in == NULL || buf_out == NULL )
465                syslog (LOG_ERR, "malloc(): %m"), pthread_exit(0);
466
467        fcntl(in_fd, F_SETFL, fcntl(in_fd, F_GETFL, 0) | O_NDELAY);
468        fcntl(out_fd, F_SETFL, fcntl(out_fd, F_GETFL, 0) | O_NDELAY);
469
470        bzero(buf_in, BUF_SIZE);
471        bzero(buf_out, BUF_SIZE);
472        do
473        {
474                bzero(buf_in, BUF_SIZE);
475                if ( (bytes_rcvd_in = recv (in_fd, buf_in, BUF_SIZE, 0)) != 0 && strlen(buf_out) > 0 )
476                {
477                        for ( i = 0; i < bytes_rcvd_out; i += bytes_sent_in )
478                        {
479                                bytes_sent_in = send (in_fd, buf_out + i, bytes_rcvd_out - i, 0);
480
481                                if ( bytes_sent_in < 0 )
482                                        break;
483                        }
484                }
485
486                bzero(buf_out, BUF_SIZE);
487                if ( (bytes_rcvd_out = recv (out_fd, buf_out, BUF_SIZE, 0)) != 0 && strlen(buf_in) > 0 )
488                {
489                        //printf("\n%s\n", buf_in);
490                        for ( i = 0; i < bytes_rcvd_in; i += bytes_sent_out )
491                        {
492                                bytes_sent_out = send (out_fd, buf_in + i, bytes_rcvd_in - i, 0);
493
494                                if ( bytes_sent_out < 0 )
495                                        break;
496                        }
497                }
498                usleep(500);
499                //sleep(1);
500                //printf("bytes_rcvd_in: %d\nbytes_rcvd_out: %d\n\n", bytes_rcvd_in, bytes_rcvd_out);
501        }
502        while ( (bytes_rcvd_in != 0) && (bytes_rcvd_out != 0) );
503
504        //puts("FIM CAT");
505
506        /*
507        if ( ((bytes_rcvd_in < 0) || (bytes_rcvd_out < 0)) && (errno != ECONNRESET) )
508                syslog (LOG_ERR, "recv(): %m"), pthread_exit(0);
509
510        if ( ((bytes_sent_in < 0) || (bytes_sent_out < 0)) && (errno != EPIPE) )
511                syslog (LOG_ERR, "send(): %m"), pthread_exit(0);
512        */
513
514        if ( user->jabber && !user->keep_alive )
515        {
516                shutdown(user->jabber, SHUT_RDWR);
517                close(user->jabber);
518        }
519        //puts("shutdown");
520        shutdown(user->in_fd, SHUT_RDWR);
521        //puts("close");
522        close(user->in_fd);
523        free (buf_in);
524        //free (buf_out);
525        pthread_exit(0);
526}
527
528// NameToAddress()
529// Convert name to an ip address.
530// Returns 0 on success, -1 on failure.
531int NameToAddr (const char * name, struct in_addr * p_inaddr)
532{
533        struct hostent * he;
534
535        // First, attempt to convert from string ip format
536        // TODO: use inet_aton() instead
537        p_inaddr->s_addr = inet_addr (name);
538        if ( p_inaddr->s_addr != -1U ) // Success
539                return 0;
540
541        // Next, attempt to read from /etc/hosts or do a DNS lookup
542        he = gethostbyname (name);
543        if ( he != NULL ) // Success
544        {
545                memcpy (p_inaddr, he->h_addr, sizeof (struct in_addr));
546                return 0;
547        }
548
549        return -1; // Failed to resolve name to an ip address
550}
551
552// NameToPort()
553// Convert name to a port number. Name can either be a port name
554// (in which case proto must also be set to either "tcp" or "udp")
555// or name can be the ascii representation of the port number.
556// Returns 0 on success, -1 on failure.
557int NameToPort (const char * name, unsigned short * port, const char * proto)
558{
559        unsigned long lport;
560        char * errpos;
561        struct servent * se;
562
563        // First, attempt to convert string to integer
564        lport = strtoul (name, &errpos, 0);
565        if ( (*errpos == 0) && (lport <= 65535) ) // Success
566        {
567                *port = lport;
568                return 0;
569        }
570
571        // Next, attempt to read the string from /etc/services
572        se = getservbyname (name, proto);
573        if ( se != NULL) // Success
574        {
575                *port = ntohs (se->s_port);
576                return 0;
577        }
578
579        return -1; // Failed to resolve port name to a number
580}
581
582// quit()
583// Print an error message to stderr
584// and syslog, then exit the program.
585void quit (const char * fmt, ...) // quit with msg
586{
587        va_list ap;
588
589        fflush (stdout);
590
591        fprintf (stderr, "%s: ", g_program_name);
592
593        va_start (ap, fmt);
594        vfprintf (stderr, fmt, ap);
595        va_end (ap);
596
597        fputc ('\n', stderr);
598
599        syslog (LOG_ERR, "I quit!");
600
601        exit (EXIT_FAILURE);
602}
603
604// pbomb()
605// Print an error message to stderr
606// and syslog, then exit the program.
607// pbomb() additionally include the
608// string representation of errno.
609void pbomb (const char * fmt, ...) // bomb with perror
610{
611        va_list ap;
612        int errno_save = errno;
613        char buf[100];
614
615        fflush (stdout);
616
617        fprintf (stderr, "%s: ", g_program_name);
618
619        va_start (ap, fmt);
620        vsnprintf (buf, sizeof (buf), fmt, ap);
621        va_end (ap);
622
623        errno = errno_save;
624        perror (buf);
625
626        syslog (LOG_ERR, "Bang!: %s: %m", buf);
627
628        exit (EXIT_FAILURE);
629}
630
631// hbomb()
632// Print an error message to stderr
633// and syslog, then exit the program.
634// hbomb() additionally include the
635// string representation of h_errno.
636void hbomb (const char * fmt, ...) // bomb with herror
637{
638        va_list ap;
639        int h_errno_save = h_errno;
640        char buf[100];
641
642        fflush (stdout);
643
644        fprintf (stderr, "%s: ", g_program_name);
645
646        va_start (ap, fmt);
647        vsnprintf (buf, sizeof (buf), fmt, ap);
648        va_end (ap);
649
650        h_errno = h_errno_save;
651        herror (buf);
652
653        syslog (LOG_ERR, "Bang!: %s: %s", buf, hstrerror (h_errno));
654
655        exit (EXIT_FAILURE);
656}
657
658// set_signal_handler()
659// Sets a signal handler function.
660// Similar to signal() but this method
661// is more portable between platforms.
662void set_signal_handler (int signum, signal_handler_t sa_handler_func)
663{
664        struct sigaction act;
665
666        act.sa_handler = sa_handler_func;
667        sigemptyset (&(act.sa_mask));
668        act.sa_flags = 0;
669
670        if ( sigaction (signum, &act, NULL) < 0 )
671        {
672                syslog (LOG_ERR, "Error setting handler for signal %d: %m", signum);
673                exit (EXIT_FAILURE);
674        }
675}
Note: See TracBrowser for help on using the repository browser.