📄 socket_server.cpp
字号:
/* Copyright (C) 2003 Chris VineThis program is distributed under the General Public Licence, version 2.For particulars of this and relevant disclaimers see the fileCOPYING distributed with the source files.*/#include <cstdlib>#include <fstream>#include <vector>#include <algorithm>#include <cstring>#include <sys/stat.h>#include <sys/types.h>#include <signal.h>#include <sys/socket.h>#include <arpa/inet.h>#include <unistd.h>#include <netdb.h>#include <errno.h>#ifdef HAVE_PTHREAD_SIGMASK #include <pthread.h>#endif#include <glibmm/convert.h>#include "socket_server.h"#ifdef ENABLE_NLS#include <libintl.h>#endif#define SAVED_FAX_FILENAME ".efax-gtk_queued_server_files"#define BUFFER_LENGTH 1024Socket_server::Socket_server(void): server_running(false), closing_socket(false), serve_sock_fd(-1), count (0), homedir(prog_config.homedir), filenames_s(new(FilenamesList)) { // we have included std::string homedir member so that we can access it in the // socket server thread created by Socket_server::start() without having to // introduce locking of accesses to prog_config.homedir by the main GUI thread // it is fine to initialise it in the initialisation list of this constructor // as prog_config.homedir is only set once, on the first call to configure_prog() // (that is, when configure_prog() is passed false as its argument) fax_to_send.second = 0; stdout_notify.connect(sigc::mem_fun(*this, &Socket_server::write_stdout_dispatcher_slot)); // make sure that we have the $HOME/efax-gtk-server directory // (we do not need to lock homedir_mutex as the socket server thread cannot // be running at this point) std::string dir_name(homedir); dir_name += "/efax-gtk-server"; mkdir(dir_name.c_str(), S_IRUSR | S_IWUSR | S_IXUSR); // now populate the queued faxes from server list read_queued_faxes();}void Socket_server::start(const std::string& port_, bool other_sock_client_address_) { if (!server_running) { port = port_; other_sock_client_address = other_sock_client_address_; server_running = true; // now block off the signals for which we have set handlers so that the socket server // thread does not receive the signals, otherwise we will have memory synchronisation // issues in multi-processor systems - we will unblock in the initial (GUI) thread // as soon as the socket server thread has been launched sigset_t sig_mask; sigemptyset(&sig_mask); sigaddset(&sig_mask, SIGCHLD); sigaddset(&sig_mask, SIGQUIT); sigaddset(&sig_mask, SIGTERM); sigaddset(&sig_mask, SIGINT); sigaddset(&sig_mask, SIGHUP);#ifdef HAVE_PTHREAD_SIGMASK pthread_sigmask(SIG_BLOCK, &sig_mask, 0);#else sigprocmask(SIG_BLOCK, &sig_mask, 0);#endif try { Glib::Thread::create(sigc::mem_fun(*this, &Socket_server::socket_thread), false); } catch (Glib::ThreadError&) { write_error("Cannot start new socket thread, fax socket will not run\n"); server_running = false; } // now unblock the signals so that the initial (GUI) thread can receive them#ifdef HAVE_PTHREAD_SIGMASK pthread_sigmask(SIG_UNBLOCK, &sig_mask, 0);#else sigprocmask(SIG_UNBLOCK, &sig_mask, 0);#endif }}void Socket_server::socket_thread(void) { { // mutex critical section Glib::Mutex::Lock lock(socket_mutex); if ((serve_sock_fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) { write_error("Cannot create socket for socket server\n"); server_running = false; return; } sockaddr_in serve_address; serve_address.sin_family = AF_INET; if (other_sock_client_address) serve_address.sin_addr.s_addr = htonl(INADDR_ANY); else { long localhost_address = inet_addr("127.0.0.1"); if (localhost_address > -1) serve_address.sin_addr.s_addr = localhost_address; else { write_error("Cannot create network address for localhost\n"); close(serve_sock_fd); serve_sock_fd = -1; server_running = false; return; } } serve_address.sin_port = htons(std::atoi(port.c_str())); if ((bind(serve_sock_fd, (sockaddr*)&serve_address, sizeof(serve_address))) < 0) { write_error("Cannot bind to socket for socket server\n"); close(serve_sock_fd); serve_sock_fd = -1; server_running = false; return; } if ((listen(serve_sock_fd, 5)) < 0) { write_error("Cannot listen on socket of socket server\n"); close(serve_sock_fd); serve_sock_fd = -1; server_running = false; return; } } // end of mutex critical section std::string message(gettext("Socket running on port ")); message += port; message += '\n'; write_stdout_from_thread(message.c_str()); // now wait for clients to connect, and continue while (accept_on_client()); write_stdout_from_thread("Closing the socket\n"); server_running = false; close_sem.post();}bool Socket_server::accept_on_client(void) { bool return_val = false; sockaddr_in connect_address; socklen_t client_len = sizeof(connect_address); int connect_sock_fd = accept(serve_sock_fd, (sockaddr*)&connect_address, &client_len); // go into mutex critical section here Glib::Mutex::Lock lock(socket_mutex); if (connect_sock_fd >= 0 && is_valid_peer(connect_address)) { std::string filename; { Glib::Mutex::Lock lock(homedir_mutex); filename = homedir; } filename += "/efax-gtk-server/efax-gtk-server-XXXXXX"; std::string::size_type size = filename.size() + 1; char* tempfile = new char[size]; std::memcpy(tempfile, filename.c_str(), size); // this will include the terminating '\0' in the copy int file_fd = mkstemp(tempfile); if (file_fd < 0) { write_error("Can't open temporary file for socket server\n" "This fax will not be processed. Is the disk full?\n"); close(connect_sock_fd); stop(); return_val = false; } else read_socket(file_fd, connect_sock_fd, tempfile); delete[] tempfile; close(connect_sock_fd); close(file_fd); return_val = true; } else if (connect_sock_fd >= 0) { // if we have got here then the peer is invalid - reject it by // closing connect_sock_fd write_error("Invalid host tried to connect to the socket server\n"); close(connect_sock_fd); return_val = true; } else if (closing_socket) closing_socket = false; // stop() has been called else{ // if we have got here, connect_sock_fd is in error condition (otherwise it // would have been picked up in the previous else_if blocks) - report the // problem write_error("There is a problem with receiving a connection on the socket server\n"); return_val = true; } return return_val;}void Socket_server::read_socket(int file_fd, int connect_sock_fd, const char* file) { char buffer[BUFFER_LENGTH]; ssize_t read_result; ssize_t write_result; while ((read_result = read(connect_sock_fd, buffer, BUFFER_LENGTH)) > 0 || read_result == -1 && errno == EINTR) { if (read_result > 0) { do { write_result = write(file_fd, buffer, read_result); } while (write_result == -1 && errno == EINTR); } } if (!read_result) { // normal close by client write_stdout_from_thread(gettext("Print job received on socket\n"));
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -