Massively cleaned up #include's, so they're in a consistent
[freeradius.git] / src / main / radiusd.c
1 /*
2  * radiusd.c    Main loop of the radius server.
3  *
4  * Version:     $Id$
5  *
6  *   This program is free software; you can redistribute it and/or modify
7  *   it under the terms of the GNU General Public License as published by
8  *   the Free Software Foundation; either version 2 of the License, or
9  *   (at your option) any later version.
10  *
11  *   This program is distributed in the hope that it will be useful,
12  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
13  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  *   GNU General Public License for more details.
15  *
16  *   You should have received a copy of the GNU General Public License
17  *   along with this program; if not, write to the Free Software
18  *   Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19  *
20  * Copyright 2000-2004,2006  The FreeRADIUS server project
21  * Copyright 1999,2000  Miquel van Smoorenburg <miquels@cistron.nl>
22  * Copyright 2000  Alan DeKok <aland@ox.org>
23  * Copyright 2000  Alan Curry <pacman-radius@cqc.com>
24  * Copyright 2000  Jeff Carneal <jeff@apex.net>
25  * Copyright 2000  Chad Miller <cmiller@surfsouth.com>
26  */
27
28 #include <freeradius-devel/ident.h>
29 RCSID("$Id$")
30
31 #include <freeradius-devel/radiusd.h>
32 #include <freeradius-devel/radius_snmp.h>
33 #include <freeradius-devel/rad_assert.h>
34
35 #include <sys/file.h>
36
37 #include <fcntl.h>
38 #include <ctype.h>
39
40 #include <signal.h>
41
42 #ifdef HAVE_GETOPT_H
43 #       include <getopt.h>
44 #endif
45
46 #ifdef HAVE_SYS_WAIT_H
47 #       include <sys/wait.h>
48 #endif
49 #ifndef WEXITSTATUS
50 #       define WEXITSTATUS(stat_val) ((unsigned)(stat_val) >> 8)
51 #endif
52 #ifndef WIFEXITED
53 #       define WIFEXITED(stat_val) (((stat_val) & 255) == 0)
54 #endif
55
56 /*
57  *  Global variables.
58  */
59 const char *progname = NULL;
60 const char *radius_dir = NULL;
61 const char *radacct_dir = NULL;
62 const char *radlog_dir = NULL;
63 const char *radlib_dir = NULL;
64 int log_stripped_names;
65 int debug_flag = 0;
66 int log_auth_detail = FALSE;
67 int need_reload = FALSE;
68
69 const char *radiusd_version = "FreeRADIUS Version " RADIUSD_VERSION ", for host " HOSTINFO ", built on " __DATE__ " at " __TIME__;
70
71 time_t time_now;
72 static pid_t radius_pid;
73 static int debug_memory = 0;
74
75 /*
76  *  Configuration items.
77  */
78 static int do_exit = 0;
79
80 /*
81  *      Static functions.
82  */
83 static void usage(int);
84
85 static void sig_fatal (int);
86 static void sig_hup (int);
87
88 /*
89  *      The main guy.
90  */
91 int main(int argc, char *argv[])
92 {
93         REQUEST *request;
94         unsigned char buffer[4096];
95         fd_set readfds;
96         int argval;
97         int pid;
98         int max_fd;
99         int status;
100         int spawn_flag = TRUE;
101         int dont_fork = FALSE;
102         int sig_hup_block = FALSE;
103         struct timeval tv, *ptv = NULL;
104
105 #ifdef HAVE_SIGACTION
106         struct sigaction act;
107 #endif
108         rad_listen_t *listener;
109
110 #ifdef OSFC2
111         set_auth_parameters(argc,argv);
112 #endif
113
114         if ((progname = strrchr(argv[0], '/')) == NULL)
115                 progname = argv[0];
116         else
117                 progname++;
118
119         debug_flag = 0;
120         spawn_flag = TRUE;
121         radius_dir = strdup(RADIUS_DIR);
122
123         /*
124          *      Ensure that the configuration is initialized.
125          */
126         memset(&mainconfig, 0, sizeof(mainconfig));
127         mainconfig.myip.af = AF_UNSPEC;
128         mainconfig.port = -1;
129         mainconfig.radiusd_conf = strdup("radiusd.conf");
130
131 #ifdef HAVE_SIGACTION
132         memset(&act, 0, sizeof(act));
133         act.sa_flags = 0 ;
134         sigemptyset( &act.sa_mask ) ;
135 #endif
136
137         /*
138          *      Don't put output anywhere until we get told a little
139          *      more.
140          */
141         mainconfig.radlog_fd = -1;
142         mainconfig.log_file = NULL;
143
144         /*  Process the options.  */
145         while ((argval = getopt(argc, argv, "Aa:bcd:fg:hi:l:mn:p:sSvxXyz")) != EOF) {
146
147                 switch(argval) {
148
149                         case 'A':
150                                 log_auth_detail = TRUE;
151                                 break;
152
153                         case 'a':
154                                 if (radacct_dir) free(radacct_dir);
155                                 radacct_dir = strdup(optarg);
156                                 break;
157
158                         case 'c':
159                                 /* ignore for backwards compatibility with Cistron */
160                                 break;
161
162                         case 'd':
163                                 if (radius_dir) free(radius_dir);
164                                 radius_dir = strdup(optarg);
165                                 break;
166
167                         case 'f':
168                                 dont_fork = TRUE;
169                                 break;
170
171                         case 'h':
172                                 usage(0);
173                                 break;
174
175                         case 'i':
176                                 if (ip_hton(optarg, AF_UNSPEC, &mainconfig.myip) < 0) {
177                                         fprintf(stderr, "radiusd: Invalid IP Address or hostname \"%s\"\n", optarg);
178                                         exit(1);
179                                 }
180                                 break;
181
182                         case 'l':
183                                 if ((strcmp(optarg, "stdout") == 0) ||
184                                     (strcmp(optarg, "stderr") == 0) ||
185                                     (strcmp(optarg, "syslog") == 0)) {
186                                         fprintf(stderr, "radiusd: -l %s is unsupported.  Use log_destination in radiusd.conf\n", optarg);
187                                         exit(1);
188                                 }
189                                 if (radlog_dir) free(radlog_dir);
190                                 radlog_dir = strdup(optarg);
191                                 break;
192
193                         case 'g':
194                                 fprintf(stderr, "radiusd: -g is unsupported.  Use log_destination in radiusd.conf.\n");
195                                 exit(1);
196                                 break;
197
198                         case 'm':
199                                 debug_memory = 1;
200                                 break;
201
202                         case 'n':
203                                 if ((strchr(optarg, '/') != NULL) ||
204                                     (strchr(optarg, '.') != NULL) ||
205                                     (strlen(optarg) > 45)) usage(1);
206
207                                 snprintf(buffer, sizeof(buffer), "%s.conf",
208                                          optarg);
209                                 if (mainconfig.radiusd_conf)
210                                         free(mainconfig.radiusd_conf);
211                                 mainconfig.radiusd_conf = strdup(buffer);
212                                 break;
213
214                         case 'S':
215                                 log_stripped_names++;
216                                 break;
217
218                         case 'p':
219                                 mainconfig.port = atoi(optarg);
220                                 if ((mainconfig.port <= 0) ||
221                                     (mainconfig.port >= 65536)) {
222                                         fprintf(stderr, "radiusd: Invalid port number %s\n", optarg);
223                                         exit(1);
224                                 }
225                                 break;
226
227                         case 's':       /* Single process mode */
228                                 spawn_flag = FALSE;
229                                 dont_fork = TRUE;
230                                 break;
231
232                         case 'v':
233                                 version();
234                                 break;
235
236                                 /*
237                                  *  BIG debugging mode for users who are
238                                  *  TOO LAZY to type '-sfxxyz -l stdout' themselves.
239                                  */
240                         case 'X':
241                                 spawn_flag = FALSE;
242                                 dont_fork = TRUE;
243                                 debug_flag += 2;
244                                 mainconfig.log_auth = TRUE;
245                                 mainconfig.log_auth_badpass = TRUE;
246                                 mainconfig.log_auth_goodpass = TRUE;
247                                 mainconfig.radlog_dest = RADLOG_STDOUT;
248                                 mainconfig.radlog_fd = STDOUT_FILENO;
249                                 break;
250
251                         case 'x':
252                                 debug_flag++;
253                                 break;
254
255                         case 'y':
256                                 mainconfig.log_auth = TRUE;
257                                 mainconfig.log_auth_badpass = TRUE;
258                                 break;
259
260                         case 'z':
261                                 mainconfig.log_auth_badpass = TRUE;
262                                 mainconfig.log_auth_goodpass = TRUE;
263                                 break;
264
265                         default:
266                                 usage(1);
267                                 break;
268                 }
269         }
270
271         /*  Read the configuration files, BEFORE doing anything else.  */
272         if (read_mainconfig(0) < 0) {
273                 exit(1);
274         }
275
276         /*
277          *  Disconnect from session
278          */
279         if (debug_flag == 0 && dont_fork == FALSE) {
280                 pid = fork();
281                 if(pid < 0) {
282                         radlog(L_ERR|L_CONS, "Couldn't fork");
283                         exit(1);
284                 }
285
286                 /*
287                  *  The parent exits, so the child can run in the background.
288                  */
289                 if (pid > 0) {
290                         exit(0);
291                 }
292 #ifdef HAVE_SETSID
293                 setsid();
294 #endif
295         }
296
297         /*
298          *      If we're NOT debugging, trap fatal signals, so we can
299          *      easily clean up after ourselves.
300          *
301          *      If we ARE debugging, don't trap them, so we can
302          *      dump core.
303          */
304         if ((mainconfig.allow_core_dumps == FALSE) && (debug_flag == 0)) {
305 #ifdef SIGSEGV
306 #ifdef HAVE_SIGACTION
307                 act.sa_handler = sig_fatal;
308                 sigaction(SIGSEGV, &act, NULL);
309 #else
310                 signal(SIGSEGV, sig_fatal);
311 #endif
312 #endif
313         }
314
315 #ifdef WITH_SNMP
316         if (mainconfig.do_snmp) radius_snmp_init();
317 #endif
318
319         /*
320          *  Ensure that we're using the CORRECT pid after forking,
321          *  NOT the one we started with.
322          */
323         radius_pid = getpid();
324
325
326         /*
327          *  Only write the PID file if we're running as a daemon.
328          *
329          *  And write it AFTER we've forked, so that we write the
330          *  correct PID.
331          */
332         if (dont_fork == FALSE) {
333                 FILE *fp;
334
335                 fp = fopen(mainconfig.pid_file, "w");
336                 if (fp != NULL) {
337                         /*
338                          *      FIXME: What about following symlinks,
339                          *      and having it over-write a normal file?
340                          */
341                         fprintf(fp, "%d\n", (int) radius_pid);
342                         fclose(fp);
343                 } else {
344                         radlog(L_ERR|L_CONS, "Failed creating PID file %s: %s\n",
345                                mainconfig.pid_file, strerror(errno));
346                         exit(1);
347                 }
348         }
349
350         /*
351          *      If we're running as a daemon, close the default file
352          *      descriptors, AFTER forking.
353          */
354         if (!debug_flag) {
355                 int devnull;
356
357                 devnull = open("/dev/null", O_RDWR);
358                 if (devnull < 0) {
359                         radlog(L_ERR|L_CONS, "Failed opening /dev/null: %s\n",
360                                strerror(errno));
361                         exit(1);
362                 }
363                 dup2(devnull, STDIN_FILENO);
364                 if (mainconfig.radlog_dest == RADLOG_STDOUT) {
365                         mainconfig.radlog_fd = dup(STDOUT_FILENO);
366                 }
367                 dup2(devnull, STDOUT_FILENO);
368                 if (mainconfig.radlog_dest == RADLOG_STDERR) {
369                         mainconfig.radlog_fd = dup(STDERR_FILENO);
370                 }
371                 dup2(devnull, STDERR_FILENO);
372                 close(devnull);
373         }
374
375         /*
376          *      It's called the thread pool, but it does a little
377          *      more than that.
378          */
379         radius_event_init(spawn_flag);
380
381         /*
382          *  Use linebuffered or unbuffered stdout if
383          *  the debug flag is on.
384          */
385         if (debug_flag == TRUE)
386                 setlinebuf(stdout);
387
388         /*
389          *      Print out which ports we're listening on.
390          */
391         for (listener = mainconfig.listen;
392              listener != NULL;
393              listener = listener->next) {
394                 listener->print(listener, buffer, sizeof(buffer));
395                 switch (listener->type) {
396                 case RAD_LISTEN_AUTH:
397                         DEBUG("Listening on authentication address %s", buffer);
398                         break;
399
400                 case RAD_LISTEN_ACCT:
401                         DEBUG("Listening on accounting address %s", buffer);
402                         break;
403
404                 case RAD_LISTEN_PROXY:
405                         DEBUG("Listening on proxy address %s", buffer);
406                         break;
407
408                 case RAD_LISTEN_DETAIL:
409                         DEBUG("Listening on detail file %s", buffer);
410                         break;
411
412                 default:
413                         break;
414                 }
415         }
416
417         /*
418          *      Now that we've set everything up, we can install the signal
419          *      handlers.  Before this, if we get any signal, we don't know
420          *      what to do, so we might as well do the default, and die.
421          */
422         signal(SIGPIPE, SIG_IGN);
423 #ifdef HAVE_SIGACTION
424         act.sa_handler = sig_hup;
425         sigaction(SIGHUP, &act, NULL);
426         act.sa_handler = sig_fatal;
427         sigaction(SIGTERM, &act, NULL);
428 #else
429         signal(SIGHUP, sig_hup);
430         signal(SIGTERM, sig_fatal);
431 #endif
432         /*
433          *      If we're debugging, then a CTRL-C will cause the
434          *      server to die immediately.  Use SIGTERM to shut down
435          *      the server cleanly in that case.
436          */
437         if ((debug_memory == 1) || (debug_flag == 0)) {
438 #ifdef HAVE_SIGACTION
439                 act.sa_handler = sig_fatal;
440                 sigaction(SIGINT, &act, NULL);
441                 sigaction(SIGQUIT, &act, NULL);
442 #else
443                 signal(SIGINT, sig_fatal);
444                 signal(SIGQUIT, sig_fatal);
445 #endif
446         }
447
448         radlog(L_INFO, "Ready to process requests.");
449
450         /*
451          *  Receive user requests
452          */
453         for (;;) {
454                 /*
455                  *      If we've been told to exit, then do so,
456                  *      even if we have data waiting.
457                  */
458                 if (do_exit) {
459                         DEBUG("Exiting...");
460
461                         /*
462                          *      Ignore the TERM signal: we're about
463                          *      to die.
464                          */
465                         signal(SIGTERM, SIG_IGN);
466
467                         /*
468                          *      Send a TERM signal to all associated
469                          *      processes (including us, which gets
470                          *      ignored.)
471                          */
472                         kill(-radius_pid, SIGTERM);
473
474                         /*
475                          *      FIXME: Kill child threads, and
476                          *      clean up?
477                          */
478
479                         /*
480                          *      FIXME: clean up any active REQUEST
481                          *      handles.
482                          */
483
484                         /*
485                          *      We're exiting, so we can delete the PID
486                          *      file.  (If it doesn't exist, we can ignore
487                          *      the error returned by unlink)
488                          */
489                         if (dont_fork == FALSE) {
490                                 unlink(mainconfig.pid_file);
491                         }
492
493                         /*
494                          *      Free the configuration items.
495                          */
496                         free_mainconfig();
497
498                         /*
499                          *      Detach any modules.
500                          */
501                         detach_modules();
502
503                         radius_event_free();
504
505                         free(radius_dir);
506
507                         /*
508                          *      SIGTERM gets do_exit=0,
509                          *      and we want to exit cleanly.
510                          *
511                          *      Other signals make us exit
512                          *      with an error status.
513                          */
514                         exit(do_exit - 1);
515                 }
516
517                 if (need_reload) {
518 #ifdef HAVE_PTHREAD_H
519                         /*
520                          *      Threads: wait for all threads to stop
521                          *      processing before re-loading the
522                          *      config, so we don't pull the rug out
523                          *      from under them.
524                          */
525                         int max_wait = 0;
526                         if (spawn_flag) for(;;) {
527                                 /*
528                                  * Block until there are '0' threads
529                                  * with a REQUEST handle.
530                                  */
531                                 sig_hup_block = TRUE;
532                                 if( (total_active_threads() == 0) ||
533                                     (max_wait >= 5) ) {
534                                         sig_hup_block = FALSE;
535                                         break;
536                                 }
537                                 sleep(1);
538                                 max_wait++;
539                         }
540 #endif
541                         if (read_mainconfig(TRUE) < 0) {
542                                 exit(1);
543                         }
544
545                         need_reload = FALSE;
546                         radlog(L_INFO, "Ready to process requests.");
547                 }
548
549                 FD_ZERO(&readfds);
550                 max_fd = 0;
551
552                 /*
553                  *      Loop over all the listening FD's.
554                  */
555                 for (listener = mainconfig.listen;
556                      listener != NULL;
557                      listener = listener->next) {
558                         if (listener->fd < 0) continue;
559
560                         FD_SET(listener->fd, &readfds);
561                         if (listener->fd > max_fd) max_fd = listener->fd;
562                 }
563
564 #ifdef WITH_SNMP
565                 if (mainconfig.do_snmp &&
566                     (rad_snmp.smux_fd >= 0)) {
567                         FD_SET(rad_snmp.smux_fd, &readfds);
568                         if (rad_snmp.smux_fd > max_fd) max_fd = rad_snmp.smux_fd;
569                 }
570 #endif
571
572                 if (!ptv) {
573                         DEBUG2("Nothing to do.  Sleeping until we see a request.");
574                 } else if (tv.tv_sec) {
575 #if 0
576                                 DEBUG2("Waking up in %d.%06d seconds...",
577                                        (int) tv.tv_sec, (int) tv.tv_usec);
578 #else
579                                 DEBUG2("Waking up in %d seconds...",
580                                        (int) tv.tv_sec);
581 #endif
582                 }
583                 status = select(max_fd + 1, &readfds, NULL, NULL, ptv);
584                 if (status == -1) {
585                         /*
586                          *      On interrupts, we clean up the request
587                          *      list.  We then continue with the loop,
588                          *      so that if we're supposed to exit,
589                          *      then the code at the start of the loop
590                          *      catches that, and exits.
591                          */
592                         if (errno == EINTR) {
593 #ifdef MEMORY_USE_DEBUGGING
594                                 /*
595                                  *      Run the server in debugging mode,
596                                  *      without threads, and give it a
597                                  *      SIGHUP.  It will clean up after
598                                  *      itself, and any memory left over
599                                  *      should be allocated by C libraries,
600                                  *      and the like.
601                                  */
602                                 detach_modules();
603                                 free_mainconfig();
604                                 exit(1);
605 #endif
606                                 continue;
607                         }
608                         radlog(L_ERR, "Unexpected error in select(): %s",
609                                         strerror(errno));
610                         exit(1);
611                 }
612
613                 time_now = time(NULL);
614 #ifndef HAVE_PTHREAD_H
615                 /*
616                  *      If there are no child threads, then there may
617                  *      be child processes.  In that case, wait for
618                  *      their exit status, and throw that exit status
619                  *      away.  This helps get rid of zxombie children.
620                  */
621                 while (waitpid(-1, &argval, WNOHANG) > 0) {
622                         /* do nothing */
623                 }
624 #endif
625
626                 /*
627                  *      Loop over the open socket FD's, reading any data.
628                  */
629                 for (listener = mainconfig.listen;
630                      listener != NULL;
631                      listener = listener->next) {
632                         RAD_REQUEST_FUNP fun;
633
634                         if ((listener->fd >= 0) &&
635                             !FD_ISSET(listener->fd, &readfds))
636                                 continue;
637
638                         /*
639                          *  Receive the packet.
640                          */
641                         if (sig_hup_block != FALSE) {
642                                 continue;
643                         }
644
645                         /*
646                          *      Do per-socket receive processing of
647                          *      the packet.  This also takes care of
648                          *      inserting the request into the event
649                          *      tree, and adding it to the queue for
650                          *      threads.
651                          */
652                         if (!listener->recv(listener, &fun, &request)) {
653                                 continue;
654                         }
655                         
656                         // EVENT FIX FIXME! Nuke this!
657
658                         /*
659                          *      Drop the request into the thread pool,
660                          *      and let the thread pool take care of
661                          *      doing something with it.
662                          */
663                         if (!thread_pool_addrequest(request, fun)) {
664                                 request->child_state = REQUEST_DONE;
665                         }
666                 } /* loop over listening sockets*/
667
668 #ifdef WITH_SNMP
669                 if (mainconfig.do_snmp) {
670                         /*
671                          *  After handling all authentication/accounting
672                          *  requests, THEN process any pending SMUX/SNMP
673                          *  queries.
674                          *
675                          *  Note that the handling is done in the main server,
676                          *  which probably isn't a Good Thing.  It really
677                          *  should be wrapped, and handled in a thread pool.
678                          */
679                         if ((rad_snmp.smux_fd >= 0) &&
680                             FD_ISSET(rad_snmp.smux_fd, &readfds) &&
681                             (rad_snmp.smux_event == SMUX_READ)) {
682                                 smux_read();
683                         }
684
685                         /*
686                          *  If we've got to re-connect, then do so now,
687                          *  before calling select again.
688                          */
689                         if (rad_snmp.smux_event == SMUX_CONNECT) {
690                                 smux_connect();
691                         }
692                 }
693 #endif
694
695                 ptv = &tv;
696                 radius_event_process(&ptv);
697
698 #ifdef HAVE_PTHREAD_H
699
700                 /*
701                  *      Only clean the thread pool if we're spawning
702                  *      child threads. 
703                  */
704                 if (spawn_flag) {
705                         thread_pool_clean(time_now);
706                 }
707 #endif
708         } /* loop forever */
709 }
710
711
712 /*
713  *  Display the syntax for starting this program.
714  */
715 static void NEVER_RETURNS usage(int status)
716 {
717         FILE *output = status?stderr:stdout;
718
719         fprintf(output,
720                         "Usage: %s [-a acct_dir] [-d db_dir] [-l log_dir] [-i address] [-AcfnsSvXxyz]\n", progname);
721         fprintf(output, "Options:\n\n");
722         fprintf(output, "  -a acct_dir     use accounting directory 'acct_dir'.\n");
723         fprintf(output, "  -A              Log auth detail.\n");
724         fprintf(output, "  -d raddb_dir    Configuration files are in \"raddbdir/*\".\n");
725         fprintf(output, "  -f              Run as a foreground process, not a daemon.\n");
726         fprintf(output, "  -h              Print this help message.\n");
727         fprintf(output, "  -i ipaddr       Listen on ipaddr ONLY\n");
728         fprintf(output, "  -l log_dir      Log file is \"log_dir/radius.log\" (not used in debug mode)\n");
729         fprintf(output, "  -p port         Listen on port ONLY\n");
730         fprintf(output, "  -s              Do not spawn child processes to handle requests.\n");
731         fprintf(output, "  -S              Log stripped names.\n");
732         fprintf(output, "  -v              Print server version information.\n");
733         fprintf(output, "  -X              Turn on full debugging.\n");
734         fprintf(output, "  -x              Turn on additional debugging. (-xx gives more debugging).\n");
735         fprintf(output, "  -y              Log authentication failures, with password.\n");
736         fprintf(output, "  -z              Log authentication successes, with password.\n");
737         exit(status);
738 }
739
740
741 /*
742  *      We got a fatal signal.
743  */
744 static void sig_fatal(int sig)
745 {
746         switch(sig) {
747                 case SIGSEGV:
748                         /* We can't really do anything intelligent here so just die */
749                         _exit(1);
750                 case SIGTERM:
751                         do_exit = 1;
752                         break;
753                 case SIGINT:
754                 case SIGQUIT:
755                         if (debug_memory) {
756                                 do_exit = 1;
757                                 break;
758                         }
759
760                 default:
761                         do_exit = 2;
762                         break;
763         }
764 }
765
766
767 /*
768  *  We got the hangup signal.
769  *  Re-read the configuration files.
770  */
771 /*ARGSUSED*/
772 static void sig_hup(int sig)
773 {
774         sig = sig; /* -Wunused */
775
776         reset_signal(SIGHUP, sig_hup);
777
778         /*
779          *  Only do the reload if we're the main server, both
780          *  for processes, and for threads.
781          */
782         if (getpid() == radius_pid) {
783                 need_reload = TRUE;
784         }
785 #ifdef WITH_SNMP
786         if (mainconfig.do_snmp) {
787                 rad_snmp.smux_failures = 0;
788                 rad_snmp.smux_event = SMUX_CONNECT;
789         }
790 #endif
791 }