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

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