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

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