27 |
#include <stdlib.h> |
#include <stdlib.h> |
28 |
#include <unistd.h> |
#include <unistd.h> |
29 |
#include <errno.h> |
#include <errno.h> |
30 |
|
#include <signal.h> |
31 |
#include <stdio.h> |
#include <stdio.h> |
32 |
#include <stdarg.h> |
#include <stdarg.h> |
33 |
#include <string.h> |
#include <string.h> |
34 |
#include <pwd.h> |
#include <pwd.h> |
|
#include <sys/types.h> |
|
35 |
#include <sys/socket.h> |
#include <sys/socket.h> |
36 |
|
#include <sys/types.h> |
37 |
|
#include <sys/wait.h> |
38 |
#include <netinet/in.h> |
#include <netinet/in.h> |
39 |
#include <arpa/inet.h> |
#include <arpa/inet.h> |
40 |
#include <netdb.h> |
#include <netdb.h> |
59 |
void |
void |
60 |
server_init (t_irc_server *server) |
server_init (t_irc_server *server) |
61 |
{ |
{ |
62 |
|
/* user choices */ |
63 |
server->name = NULL; |
server->name = NULL; |
64 |
server->autoconnect = 0; |
server->autoconnect = 0; |
65 |
server->autoreconnect = 1; |
server->autoreconnect = 1; |
76 |
server->command = NULL; |
server->command = NULL; |
77 |
server->command_delay = 1; |
server->command_delay = 1; |
78 |
server->autojoin = NULL; |
server->autojoin = NULL; |
79 |
|
server->autorejoin = 0; |
80 |
|
|
81 |
|
/* internal vars */ |
82 |
|
server->child_pid = 0; |
83 |
|
server->child_read = -1; |
84 |
|
server->child_write = -1; |
85 |
|
server->sock4 = -1; |
86 |
|
server->is_connected = 0; |
87 |
server->unterminated_message = NULL; |
server->unterminated_message = NULL; |
88 |
server->nick = NULL; |
server->nick = NULL; |
|
server->is_connected = 0; |
|
89 |
server->reconnect_start = 0; |
server->reconnect_start = 0; |
90 |
server->reconnect_join = 0; |
server->reconnect_join = 0; |
|
server->sock4 = -1; |
|
|
server->server_read = -1; |
|
|
server->server_write = -1; |
|
91 |
server->is_away = 0; |
server->is_away = 0; |
92 |
server->away_time = 0; |
server->away_time = 0; |
93 |
server->lag = 0; |
server->lag = 0; |
650 |
} |
} |
651 |
|
|
652 |
/* |
/* |
653 |
* server_connect: connect to an IRC server |
* server_kill_child: kill child process and close pipe |
654 |
|
*/ |
655 |
|
|
656 |
|
void |
657 |
|
server_kill_child (t_irc_server *server) |
658 |
|
{ |
659 |
|
/* kill process */ |
660 |
|
if (server->child_pid > 0) |
661 |
|
{ |
662 |
|
kill (server->child_pid, SIGKILL); |
663 |
|
waitpid (server->child_pid, NULL, 0); |
664 |
|
server->child_pid = 0; |
665 |
|
} |
666 |
|
|
667 |
|
/* close pipe used with child */ |
668 |
|
if (server->child_read != -1) |
669 |
|
{ |
670 |
|
close (server->child_read); |
671 |
|
server->child_read = -1; |
672 |
|
} |
673 |
|
if (server->child_write != -1) |
674 |
|
{ |
675 |
|
close (server->child_write); |
676 |
|
server->child_write = -1; |
677 |
|
} |
678 |
|
} |
679 |
|
|
680 |
|
/* |
681 |
|
* server_close_connection: close server connection (kill child, close socket/pipes) |
682 |
|
*/ |
683 |
|
|
684 |
|
void |
685 |
|
server_close_connection (t_irc_server *server) |
686 |
|
{ |
687 |
|
server_kill_child (server); |
688 |
|
|
689 |
|
/* close network socket */ |
690 |
|
if (server->sock4 != -1) |
691 |
|
{ |
692 |
|
close (server->sock4); |
693 |
|
server->sock4 = -1; |
694 |
|
} |
695 |
|
|
696 |
|
/* free any pending message */ |
697 |
|
if (server->unterminated_message) |
698 |
|
{ |
699 |
|
free (server->unterminated_message); |
700 |
|
server->unterminated_message = NULL; |
701 |
|
} |
702 |
|
|
703 |
|
/* server is now disconnected */ |
704 |
|
server->is_connected = 0; |
705 |
|
} |
706 |
|
|
707 |
|
/* |
708 |
|
* server_reconnect_schedule: schedule reconnect for a server |
709 |
|
*/ |
710 |
|
|
711 |
|
void |
712 |
|
server_reconnect_schedule (t_irc_server *server) |
713 |
|
{ |
714 |
|
if (server->autoreconnect) |
715 |
|
{ |
716 |
|
server->reconnect_start = time (NULL); |
717 |
|
irc_display_prefix (server->buffer, PREFIX_INFO); |
718 |
|
gui_printf (server->buffer, _("%s: Reconnecting to server in %d seconds\n"), |
719 |
|
PACKAGE_NAME, server->autoreconnect_delay); |
720 |
|
} |
721 |
|
else |
722 |
|
server->reconnect_start = 0; |
723 |
|
} |
724 |
|
|
725 |
|
/* |
726 |
|
* server_child_read: read connection progress from child process |
727 |
|
*/ |
728 |
|
|
729 |
|
void |
730 |
|
server_child_read (t_irc_server *server) |
731 |
|
{ |
732 |
|
char buffer[1]; |
733 |
|
int num_read; |
734 |
|
|
735 |
|
num_read = read (server->child_read, buffer, sizeof (buffer)); |
736 |
|
if (num_read != -1) |
737 |
|
{ |
738 |
|
switch (buffer[0]) |
739 |
|
{ |
740 |
|
/* connection OK */ |
741 |
|
case '0': |
742 |
|
server_kill_child (server); |
743 |
|
irc_login (server); |
744 |
|
break; |
745 |
|
/* adress not found */ |
746 |
|
case '1': |
747 |
|
irc_display_prefix (server->buffer, PREFIX_ERROR); |
748 |
|
gui_printf (server->buffer, |
749 |
|
_("%s address \"%s\" not found\n"), |
750 |
|
WEECHAT_ERROR, server->address); |
751 |
|
server_close_connection (server); |
752 |
|
server_reconnect_schedule (server); |
753 |
|
break; |
754 |
|
/* IP address not found */ |
755 |
|
case '2': |
756 |
|
irc_display_prefix (server->buffer, PREFIX_ERROR); |
757 |
|
gui_printf (server->buffer, |
758 |
|
_("%s IP address not found\n"), WEECHAT_ERROR); |
759 |
|
server_close_connection (server); |
760 |
|
server_reconnect_schedule (server); |
761 |
|
break; |
762 |
|
/* connection refused */ |
763 |
|
case '3': |
764 |
|
irc_display_prefix (server->buffer, PREFIX_ERROR); |
765 |
|
gui_printf (server->buffer, |
766 |
|
_("%s connection refused\n"), WEECHAT_ERROR); |
767 |
|
server_close_connection (server); |
768 |
|
server_reconnect_schedule (server); |
769 |
|
break; |
770 |
|
} |
771 |
|
} |
772 |
|
} |
773 |
|
|
774 |
|
/* |
775 |
|
* server_child: child process trying to connect to server |
776 |
*/ |
*/ |
777 |
|
|
778 |
int |
int |
779 |
server_connect (t_irc_server *server) |
server_child (t_irc_server *server) |
780 |
{ |
{ |
|
int set; |
|
781 |
struct hostent *ip4_hostent; |
struct hostent *ip4_hostent; |
782 |
struct sockaddr_in addr; |
struct sockaddr_in addr; |
783 |
char *ip_address; |
char *ip_address; |
784 |
int error; |
int error; |
785 |
int server_pipe[2]; |
|
786 |
|
/* bind to hostname */ |
787 |
|
ip4_hostent = gethostbyname (server->address); |
788 |
|
if (!ip4_hostent) |
789 |
|
{ |
790 |
|
write (server->child_write, "1", 1); |
791 |
|
return 0; |
792 |
|
} |
793 |
|
memset (&addr, 0, sizeof (addr)); |
794 |
|
memcpy (&addr.sin_addr, ip4_hostent->h_addr, ip4_hostent->h_length); |
795 |
|
addr.sin_port = htons (server->port); |
796 |
|
addr.sin_family = AF_INET; |
797 |
|
|
798 |
|
/* find IP address */ |
799 |
|
ip_address = inet_ntoa (addr.sin_addr); |
800 |
|
if (!ip_address) |
801 |
|
{ |
802 |
|
write (server->child_write, "2", 1); |
803 |
|
return 0; |
804 |
|
} |
805 |
|
|
806 |
|
/* connect to server */ |
807 |
|
error = connect (server->sock4, (struct sockaddr *) &addr, sizeof (addr)); |
808 |
|
if (error != 0) |
809 |
|
{ |
810 |
|
write (server->child_write, "3", 1); |
811 |
|
return 0; |
812 |
|
} |
813 |
|
|
814 |
|
/* connection OK */ |
815 |
|
write (server->child_write, "0", 1); |
816 |
|
|
817 |
|
return 0; |
818 |
|
} |
819 |
|
|
820 |
|
/* |
821 |
|
* server_connect: connect to an IRC server |
822 |
|
*/ |
823 |
|
|
824 |
|
int |
825 |
|
server_connect (t_irc_server *server) |
826 |
|
{ |
827 |
|
int child_pipe[2], set; |
828 |
|
pid_t pid; |
829 |
|
|
830 |
irc_display_prefix (server->buffer, PREFIX_INFO); |
irc_display_prefix (server->buffer, PREFIX_INFO); |
831 |
gui_printf (server->buffer, |
gui_printf (server->buffer, |
833 |
PACKAGE_NAME, server->address, server->port); |
PACKAGE_NAME, server->address, server->port); |
834 |
wee_log_printf (_("connecting to server %s:%d...\n"), |
wee_log_printf (_("connecting to server %s:%d...\n"), |
835 |
server->address, server->port); |
server->address, server->port); |
836 |
server->is_connected = 0; |
|
837 |
|
/* close any opened connection and kill child process if running */ |
838 |
/* create pipe */ |
server_close_connection (server); |
839 |
if (pipe (server_pipe) < 0) |
|
840 |
|
/* create pipe for child process */ |
841 |
|
if (pipe (child_pipe) < 0) |
842 |
{ |
{ |
843 |
irc_display_prefix (server->buffer, PREFIX_ERROR); |
irc_display_prefix (server->buffer, PREFIX_ERROR); |
844 |
gui_printf (server->buffer, |
gui_printf (server->buffer, |
845 |
_("%s cannot create pipe\n"), WEECHAT_ERROR); |
_("%s cannot create pipe\n"), WEECHAT_ERROR); |
|
server_free (server); |
|
846 |
return 0; |
return 0; |
847 |
} |
} |
848 |
server->server_read = server_pipe[0]; |
server->child_read = child_pipe[0]; |
849 |
server->server_write = server_pipe[1]; |
server->child_write = child_pipe[1]; |
850 |
|
|
851 |
/* create socket and set options */ |
/* create socket and set options */ |
852 |
server->sock4 = socket (AF_INET, SOCK_STREAM, 0); |
server->sock4 = socket (AF_INET, SOCK_STREAM, 0); |
853 |
set = 1; |
if (server->sock4 == -1) |
|
if (setsockopt |
|
|
(server->sock4, SOL_SOCKET, SO_REUSEADDR, (char *) &set, |
|
|
sizeof (set)) == -1) |
|
854 |
{ |
{ |
855 |
irc_display_prefix (server->buffer, PREFIX_ERROR); |
irc_display_prefix (server->buffer, PREFIX_ERROR); |
856 |
gui_printf (server->buffer, |
gui_printf (server->buffer, |
857 |
_("%s cannot set socket option \"SO_REUSEADDR\"\n"), |
_("%s cannot create socket\n"), WEECHAT_ERROR); |
858 |
WEECHAT_ERROR); |
server_close_connection (server); |
859 |
|
return 0; |
860 |
} |
} |
861 |
|
|
862 |
|
/* set SO_REUSEADDR option for socket */ |
863 |
set = 1; |
set = 1; |
864 |
if (setsockopt |
if (setsockopt (server->sock4, SOL_SOCKET, SO_REUSEADDR, |
865 |
(server->sock4, SOL_SOCKET, SO_KEEPALIVE, (char *) &set, |
(void *) &set, sizeof (set)) == -1) |
|
sizeof (set)) == -1) |
|
866 |
{ |
{ |
867 |
irc_display_prefix (server->buffer, PREFIX_ERROR); |
irc_display_prefix (server->buffer, PREFIX_ERROR); |
868 |
gui_printf (server->buffer, |
gui_printf (server->buffer, |
869 |
_("%s cannot set socket option \"SO_KEEPALIVE\"\n"), |
_("%s cannot set socket option \"SO_REUSEADDR\"\n"), |
870 |
WEECHAT_ERROR); |
WEECHAT_WARNING); |
|
} |
|
|
|
|
|
/* bind to hostname */ |
|
|
ip4_hostent = gethostbyname (server->address); |
|
|
if (!ip4_hostent) |
|
|
{ |
|
|
irc_display_prefix (server->buffer, PREFIX_ERROR); |
|
|
gui_printf (server->buffer, |
|
|
_("%s address \"%s\" not found\n"), |
|
|
WEECHAT_ERROR, server->address); |
|
|
close (server->server_read); |
|
|
close (server->server_write); |
|
|
close (server->sock4); |
|
|
server->sock4 = -1; |
|
|
return 0; |
|
871 |
} |
} |
872 |
memset (&addr, 0, sizeof (addr)); |
|
873 |
memcpy (&addr.sin_addr, ip4_hostent->h_addr, ip4_hostent->h_length); |
/* set SO_KEEPALIVE option for socket */ |
874 |
addr.sin_port = htons (server->port); |
set = 1; |
875 |
addr.sin_family = AF_INET; |
if (setsockopt (server->sock4, SOL_SOCKET, SO_KEEPALIVE, |
876 |
/*error = bind(server->sock4, (struct sockaddr *)(&addr), sizeof(addr)); |
(void *) &set, sizeof (set)) == -1) |
|
if (error != 0) |
|
|
{ |
|
|
irc_display_prefix (server->buffer, PREFIX_ERROR); |
|
|
gui_printf (server->buffer, |
|
|
_("%s can't bind to hostname\n"), WEECHAT_ERROR); |
|
|
return 0; |
|
|
}*/ |
|
|
ip_address = inet_ntoa (addr.sin_addr); |
|
|
if (!ip_address) |
|
877 |
{ |
{ |
878 |
irc_display_prefix (server->buffer, PREFIX_ERROR); |
irc_display_prefix (server->buffer, PREFIX_ERROR); |
879 |
gui_printf (server->buffer, |
gui_printf (server->buffer, |
880 |
_("%s IP address not found\n"), WEECHAT_ERROR); |
_("%s cannot set socket option \"SO_KEEPALIVE\"\n"), |
881 |
close (server->server_read); |
WEECHAT_WARNING); |
|
close (server->server_write); |
|
|
close (server->sock4); |
|
|
server->sock4 = -1; |
|
|
return 0; |
|
882 |
} |
} |
883 |
|
|
884 |
/* connection to server */ |
switch (pid = fork ()) |
|
irc_display_prefix (server->buffer, PREFIX_INFO); |
|
|
gui_printf (server->buffer, |
|
|
_("%s: server IP is: %s\n"), PACKAGE_NAME, ip_address); |
|
|
|
|
|
error = connect (server->sock4, (struct sockaddr *) &addr, sizeof (addr)); |
|
|
if (error != 0) |
|
885 |
{ |
{ |
886 |
irc_display_prefix (server->buffer, PREFIX_ERROR); |
/* fork failed */ |
887 |
gui_printf (server->buffer, |
case -1: |
888 |
_("%s cannot connect to irc server\n"), WEECHAT_ERROR); |
server_close_connection (server); |
889 |
close (server->server_read); |
return 0; |
890 |
close (server->server_write); |
/* child process */ |
891 |
close (server->sock4); |
case 0: |
892 |
server->sock4 = -1; |
setuid (getuid ()); |
893 |
return 0; |
server_child (server); |
894 |
|
_exit (EXIT_SUCCESS); |
895 |
} |
} |
896 |
|
|
897 |
|
/* parent process go on here */ |
898 |
|
server->child_pid = pid; |
899 |
|
|
900 |
return 1; |
return 1; |
901 |
} |
} |
902 |
|
|
913 |
server->reconnect_start = 0; |
server->reconnect_start = 0; |
914 |
|
|
915 |
if (server_connect (server)) |
if (server_connect (server)) |
|
{ |
|
916 |
server->reconnect_join = 1; |
server->reconnect_join = 1; |
|
irc_login (server); |
|
|
} |
|
917 |
else |
else |
918 |
{ |
server_reconnect_schedule (server); |
|
server->reconnect_start = time (NULL); |
|
|
irc_display_prefix (server->buffer, PREFIX_INFO); |
|
|
gui_printf (server->buffer, _("%s: Reconnecting to server in %d seconds\n"), |
|
|
PACKAGE_NAME, server->autoreconnect_delay); |
|
|
} |
|
919 |
} |
} |
920 |
|
|
921 |
/* |
/* |
934 |
|| ((!command_line) && (ptr_server->autoconnect)) ) |
|| ((!command_line) && (ptr_server->autoconnect)) ) |
935 |
{ |
{ |
936 |
(void) gui_buffer_new (gui_current_window, ptr_server, NULL, 0, 1); |
(void) gui_buffer_new (gui_current_window, ptr_server, NULL, 0, 1); |
937 |
if (server_connect (ptr_server)) |
gui_redraw_buffer (gui_current_window->buffer); |
938 |
irc_login (ptr_server); |
server_connect (ptr_server); |
939 |
} |
} |
940 |
} |
} |
941 |
} |
} |
961 |
} |
} |
962 |
} |
} |
963 |
|
|
964 |
/* close communication with server */ |
irc_display_prefix (server->buffer, PREFIX_INFO); |
965 |
if (server->server_read >= 0) |
gui_printf (server->buffer, _("Disconnected from server!\n")); |
|
close (server->server_read); |
|
|
server->server_read = -1; |
|
|
|
|
|
if (server->server_write >= 0) |
|
|
close (server->server_write); |
|
|
server->server_write = -1; |
|
|
|
|
|
if (server->sock4 >= 0) |
|
|
close (server->sock4); |
|
|
server->sock4 = -1; |
|
966 |
|
|
967 |
if (server->unterminated_message) |
server_close_connection (server); |
|
free (server->unterminated_message); |
|
|
server->unterminated_message = NULL; |
|
968 |
|
|
|
server->is_connected = 0; |
|
969 |
server->is_away = 0; |
server->is_away = 0; |
970 |
server->away_time = 0; |
server->away_time = 0; |
971 |
server->lag = 0; |
server->lag = 0; |
974 |
server->lag_next_check = time (NULL) + cfg_irc_lag_check; |
server->lag_next_check = time (NULL) + cfg_irc_lag_check; |
975 |
|
|
976 |
if ((reconnect) && (server->autoreconnect)) |
if ((reconnect) && (server->autoreconnect)) |
977 |
{ |
server_reconnect_schedule (server); |
|
server->reconnect_start = time (NULL); |
|
|
irc_display_prefix (server->buffer, PREFIX_INFO); |
|
|
gui_printf (server->buffer, _("%s: Reconnecting to server in %d seconds\n"), |
|
|
PACKAGE_NAME, server->autoreconnect_delay); |
|
|
} |
|
978 |
else |
else |
979 |
server->reconnect_start = 0; |
server->reconnect_start = 0; |
980 |
|
|