1 /** @file scim_socket.cpp
2 * @brief Implementation of Socket related classes.
5 /* ISF is based on SCIM 1.4.7 and extended for supporting more mobile fitable. */
8 * Smart Common Input Method
10 * Copyright (c) 2002-2005 James Su <suzhe@tsinghua.org.cn>
11 * Copyright (c) 2012-2013 Samsung Electronics Co., Ltd.
14 * This library is free software; you can redistribute it and/or
15 * modify it under the terms of the GNU Lesser General Public
16 * License as published by the Free Software Foundation; either
17 * version 2 of the License, or (at your option) any later version.
19 * This library is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU Lesser General Public License for more details.
24 * You should have received a copy of the GNU Lesser General Public
25 * License along with this program; if not, write to the
26 * Free Software Foundation, Inc., 59 Temple Place, Suite 330,
27 * Boston, MA 02111-1307 USA
29 * Modifications by Samsung Electronics Co., Ltd.
30 * 1. Add filter_event () and filter_exception_event () in SocketServer class
31 * 2. Add set_nonblock_mode () in Socket class
33 * $Id: scim_socket.cpp,v 1.44 2005/12/01 08:27:36 suzhe Exp $
37 #define Uses_SCIM_SOCKET
38 #define Uses_SCIM_TRANSACTION
39 #define Uses_SCIM_CONFIG_PATH
40 #include <sys/types.h>
41 #include <sys/socket.h>
50 #include <netinet/in.h>
52 #include <arpa/inet.h>
58 #include "scim_private.h"
61 /* Experimental modification for avoiding multiple scim process problem */
62 #define DISABLE_MULTIPLE_SOCKETS
64 #define SCIM_SOCKET_SERVER_MAX_CLIENTS 256
69 __gethostname (const char *host)
71 struct in_addr addr = { 0 };
73 #if HAVE_GETHOSTBYNAME_R
74 struct hostent hostbuf, *hp;
81 /* Allocate buffer, remember to free it to avoid memory leakage. */
82 tmphstbuf = (char*) malloc (hstbuflen);
84 while ((res = gethostbyname_r (host, &hostbuf, tmphstbuf, hstbuflen, &hp, &herr)) == ERANGE) {
85 /* Enlarge the buffer. */
87 tmphstbuf = (char*) realloc (tmphstbuf, hstbuflen);
92 addr = * ((struct in_addr *)hp->h_addr_list [0]);
97 struct hostent *hostinfo;
99 hostinfo = gethostbyname (host);
102 addr = * ((struct in_addr *) hostinfo->h_addr_list [0]);
107 class SocketAddress::SocketAddressImpl
109 struct sockaddr *m_data;
110 SocketFamily m_family;
114 SocketAddressImpl (const String &addr = String ())
115 : m_data (0), m_family (SCIM_SOCKET_UNKNOWN) {
116 if (addr.length ()) set_address (addr);
119 SocketAddressImpl (const SocketAddressImpl &other)
120 : m_data (0), m_family (other.m_family), m_address (other.m_address) {
124 case SCIM_SOCKET_LOCAL:
125 m_data = (struct sockaddr*) new struct sockaddr_un;
126 len = sizeof (sockaddr_un);
128 case SCIM_SOCKET_INET:
129 m_data = (struct sockaddr*) new struct sockaddr_in;
130 len = sizeof (sockaddr_in);
132 case SCIM_SOCKET_UNKNOWN:
136 if (len && m_data) memcpy (m_data, other.m_data, len);
140 ~SocketAddressImpl () {
141 if (m_data) delete m_data;
144 void swap (SocketAddressImpl &other) {
145 std::swap (m_data, other.m_data);
146 std::swap (m_family, other.m_family);
147 std::swap (m_address, other.m_address);
150 bool valid () const {
151 if (m_address.length () && m_data &&
152 (m_family == SCIM_SOCKET_LOCAL || m_family == SCIM_SOCKET_INET))
157 SocketFamily get_family () const {
161 bool set_address (const String &addr);
163 const String & get_address () const {
167 const void * get_data () const {
168 return (void *)m_data;
171 int get_data_length () const {
173 if (m_family == SCIM_SOCKET_LOCAL)
174 return SUN_LEN ((struct sockaddr_un*)(m_data));
175 else if (m_family == SCIM_SOCKET_INET)
176 return sizeof (struct sockaddr_in);
183 SocketAddress::SocketAddressImpl::set_address (const String &addr)
185 std::vector <String> varlist;
187 struct sockaddr *new_data = 0;
188 SocketFamily new_family = SCIM_SOCKET_UNKNOWN;
190 scim_split_string_list (varlist, addr, ':');
192 if (varlist.size () < 2)
195 if (varlist [0] == "local" || varlist [0] == "unix" || varlist [0] == "file") {
196 #ifdef DISABLE_MULTIPLE_SOCKETS
197 String real_addr = addr.substr (varlist [0].length ()+1);
199 String real_addr = addr.substr (varlist [0].length ()+1) +
201 scim_get_user_name ();
203 struct sockaddr_un *un = new struct sockaddr_un;
205 un->sun_family = AF_UNIX;
207 memset (un->sun_path, 0, sizeof (un->sun_path));
209 strncpy (un->sun_path, real_addr.c_str (), sizeof (un->sun_path));
211 un->sun_path[sizeof (un->sun_path) - 1] = '\0';
213 SCIM_DEBUG_SOCKET(3) << " local:" << un->sun_path << "\n";
215 new_family = SCIM_SOCKET_LOCAL;
216 new_data = (struct sockaddr *) un;
218 } else if ((varlist [0] == "tcp" || varlist [0] == "inet") &&
219 varlist.size () == 3) {
221 struct sockaddr_in *in = new struct sockaddr_in;
223 in->sin_addr = __gethostname (varlist [1].c_str ());
225 if (in->sin_addr.s_addr) {
226 in->sin_family = AF_INET;
227 in->sin_port = htons (atoi (varlist [2].c_str ()));
229 SCIM_DEBUG_SOCKET(3) << " inet:"
230 << inet_ntoa (in->sin_addr) << ":"
231 << ntohs (in->sin_port) << "\n";
233 new_family = SCIM_SOCKET_INET;
234 new_data = (struct sockaddr *) in;
241 if (m_data) delete m_data;
244 m_family = new_family;
252 // Implementation of SocketAddress
253 SocketAddress::SocketAddress (const String &addr)
254 : m_impl (new SocketAddressImpl (addr))
258 SocketAddress::SocketAddress (const SocketAddress &addr)
259 : m_impl (new SocketAddressImpl (*addr.m_impl))
263 SocketAddress::~SocketAddress ()
269 SocketAddress::operator = (const SocketAddress &addr)
272 SocketAddressImpl new_impl (*addr.m_impl);
273 m_impl->swap (new_impl);
279 SocketAddress::valid () const
281 return m_impl->valid ();
285 SocketAddress::get_family () const
287 return m_impl->get_family ();
291 SocketAddress::set_address (const String &addr)
293 SCIM_DEBUG_SOCKET(2) << " SocketAddress::set_address (" << addr << ")\n";
294 return m_impl->set_address (addr);
298 SocketAddress::get_address () const
300 return m_impl->get_address ();
304 SocketAddress::get_data () const
306 return m_impl->get_data ();
310 SocketAddress::get_data_length () const
312 return m_impl->get_data_length ();
315 // Implementation of Socket
316 class Socket::SocketImpl
322 SocketFamily m_family;
323 SocketAddress m_address;
327 SocketImpl (int id = -1)
328 : m_id (id), m_err (0), m_binded (false), m_no_close (true),
329 m_family (SCIM_SOCKET_UNKNOWN) {
336 bool valid () const {
340 int read (void *buf, size_t size) {
341 if (!buf || !size) { m_err = EINVAL; return -1; }
342 if (m_id < 0) { m_err = EBADF; return -1; }
347 ret = ::read (m_id, buf, size);
357 int read_with_timeout (void *buf, size_t size, int timeout) {
358 if (!buf || !size) { m_err = EINVAL; return -1; }
359 if (m_id < 0) { m_err = EBADF; return -1; }
362 return read (buf, size);
366 char *cbuf = static_cast<char *> (buf);
369 ret = wait_for_data_internal (&timeout);
371 if (ret < 0) return ret;
372 if (ret == 0) return nbytes;
374 ret = read (cbuf, size);
376 if (ret < 0) return ret;
377 if (ret == 0) return nbytes;
386 int write (const void *buf, size_t size) {
387 if (!buf || !size) { m_err = EINVAL; return -1; }
388 if (m_id < 0) { m_err = EBADF; return -1; }
392 typedef void (*_scim_sighandler_t)(int);
393 _scim_sighandler_t orig_handler = signal (SIGPIPE, SIG_IGN);
397 const char *cbuf = static_cast<const char*> (buf);
400 ret = ::write (m_id, cbuf, size);
402 size -= (size_t) ret;
413 if (orig_handler != SIG_ERR)
414 signal (SIGPIPE, orig_handler);
416 signal (SIGPIPE, SIG_DFL);
421 int wait_for_data (int timeout = -1) {
422 if (m_id < 0) { m_err = EBADF; return -1; }
423 return wait_for_data_internal (&timeout);
426 int get_error_number () const {
430 String get_error_message () const {
432 return String (strerror (m_err));
436 int get_id () const {
440 int set_nonblock_mode () {
441 if (m_id < 0) { m_err = EBADF; return -1; }
445 ret = ::fcntl(m_id, F_SETFL, O_NONBLOCK);
449 bool connect (const SocketAddress &addr) {
450 SCIM_DEBUG_SOCKET(1) << "Socket: Connect to server: "
451 << addr.get_address () << " ...\n";
455 if (m_binded) return false;
457 if (addr.valid () && m_id >= 0 && m_family == addr.get_family ()) {
458 struct sockaddr * data = (sockaddr *) addr.get_data ();
459 int len = addr.get_data_length ();
461 // Backup the current flag to restore after non-blocking connect() try
462 int flags = fcntl (m_id, F_GETFL, 0);
463 fcntl (m_id, F_SETFL, flags | O_NONBLOCK);
466 snprintf (buf, sizeof (buf), "time:%ld pid:%d ppid:%d %s %s trying connect() to %s\n",
467 time (0), getpid (), getppid (), __FILE__, __func__, addr.get_address ().c_str ());
470 if ((m_err = ::connect (m_id, data, len)) == 0) {
471 if (fcntl (m_id, F_SETFL, flags) == -1) {
476 snprintf (buf, sizeof (buf), "time:%ld pid:%d %s %s connect() succeeded\n",
477 time (0), getpid (), __FILE__, __func__);
483 // If still in progress, use select() to wait for the connection result
484 if (m_err == EINPROGRESS) {
485 const int nsec = scim_get_default_socket_timeout () / 1000;
495 snprintf (buf, sizeof (buf), "time:%ld pid:%d %s %s EINPROGRESS, select() with timeout %d\n",
496 time (0), getpid (), __FILE__, __func__, nsec);
499 if (select (m_id + 1, &rset, &wset, NULL, nsec ? &tval : NULL) == 0) {
502 snprintf (buf, sizeof (buf), "time:%ld pid:%d %s %s timeout in select()\n",
503 time (0), getpid (), __FILE__, __func__);
506 // We've got something, connection succeeded
507 snprintf (buf, sizeof (buf), "time:%ld pid:%d %s %s finally connected\n",
508 time (0), getpid (), __FILE__, __func__);
511 if (fcntl (m_id, F_SETFL, flags) == -1) {
519 snprintf (buf, sizeof (buf), "time:%ld pid:%d %s %s connect() failed with %d\n",
520 time (0), getpid (), __FILE__, __func__, errno);
523 if (fcntl (m_id, F_SETFL, flags) == -1) {
530 bool bind (const SocketAddress &addr) {
531 SCIM_DEBUG_SOCKET(1) << "Socket: Bind to address: "
532 << addr.get_address () << " ...\n";
536 if (m_binded) return false;
538 if (addr.valid () && m_id >= 0 && m_family == addr.get_family ()) {
539 const struct sockaddr_un * data_un = 0;
540 const struct sockaddr * data = static_cast <const struct sockaddr *>(addr.get_data ());
541 int len = addr.get_data_length ();
543 // Unlink the broken socket file.
544 if (m_family == SCIM_SOCKET_LOCAL) {
545 data_un = static_cast <const struct sockaddr_un *>(addr.get_data ());
546 // The file is already exist, check if it's broken
547 // by connecting to it.
548 SCIM_DEBUG_SOCKET(2) << "Try to remove the broken socket file: " << data_un->sun_path << "\n";
550 if (::access (data_un->sun_path, F_OK) == 0) {
551 SocketClient tmp_socket (addr);
553 if (!tmp_socket.is_connected ()) {
556 // If it's a socket file, then
558 if (::stat (data_un->sun_path, &statbuf) == 0 && S_ISSOCK (statbuf.st_mode))
559 ::unlink (data_un->sun_path);
566 if (::bind (m_id, data, len) == 0) {
571 // Set correct permission for the socket file
572 #ifdef DISABLE_MULTIPLE_SOCKETS
573 if (m_family == SCIM_SOCKET_LOCAL) {
574 ::chmod (data_un->sun_path, S_IRUSR | S_IWUSR | S_IROTH | S_IWOTH);
577 if (m_family == SCIM_SOCKET_LOCAL) {
578 ::chmod (data_un->sun_path, S_IRUSR | S_IWUSR);
590 bool listen (int queue_length = 5) {
591 if (m_id < 0) { m_err = EBADF; return -1; }
593 SCIM_DEBUG_SOCKET(1) << "Socket: Listen: "
594 << queue_length << " ...\n";
598 int ret = ::listen (m_id, queue_length);
600 if (ret < 0) m_err = errno;
606 if (m_id < 0) { m_err = EBADF; return -1; }
613 if (m_family == SCIM_SOCKET_LOCAL) {
614 struct sockaddr_un addr;
615 addrlen = sizeof (addr);
616 ret = ::accept (m_id, (struct sockaddr*) &addr, (socklen_t*) &addrlen);
617 } else if (m_family == SCIM_SOCKET_INET) {
618 struct sockaddr_in addr;
619 addrlen = sizeof (addr);
620 ret = ::accept (m_id, (struct sockaddr*) &addr, (socklen_t*) &addrlen);
623 if (ret < 0 && addrlen > 0)
626 SCIM_DEBUG_SOCKET(1) << "Socket: Accept connection, ret: " << ret << "\n";
631 bool create (SocketFamily family) {
634 if (family == SCIM_SOCKET_LOCAL)
635 ret = ::socket (PF_UNIX, SOCK_STREAM, 0);
636 else if (family == SCIM_SOCKET_INET)
637 ret = ::socket (PF_INET, SOCK_STREAM, 0);
644 if (m_id >= 0) close ();
654 SCIM_DEBUG_SOCKET(1) << "Socket: Socket created, family: "
655 << family << " ret: " << ret << "\n";
661 if (m_id < 0) return;
664 SCIM_DEBUG_SOCKET(2) << " Closing the socket: " << m_id << " ...\n";
667 // Unlink the socket file.
669 if (m_binded && m_family == SCIM_SOCKET_LOCAL) {
670 const struct sockaddr_un * data = static_cast <const struct sockaddr_un *>(m_address.get_data ());
671 // FIXME: Don't unlink the socket file, because if the process is forked and child process exits
672 // the socket file will be unlinked by child process.
673 //SCIM_DEBUG_SOCKET(3) << " Unlinking socket file " << data->sun_path << "...\n";
674 ::unlink (data->sun_path);
683 m_family = SCIM_SOCKET_UNKNOWN;
684 m_address = SocketAddress ();
688 int wait_for_data_internal (int *timeout) {
691 struct timeval begin_tv;
695 gettimeofday(&begin_tv, 0);
696 tv.tv_sec = *timeout / 1000;
697 tv.tv_usec = (*timeout % 1000) * 1000;
706 ret = select(m_id + 1, &fds, NULL, NULL, (*timeout >= 0) ? &tv : NULL);
709 struct timeval cur_tv;
710 gettimeofday (&cur_tv, 0);
711 elapsed = (cur_tv.tv_sec - begin_tv.tv_sec) * 1000 +
712 (cur_tv.tv_usec - begin_tv.tv_usec) / 1000;
713 *timeout = *timeout - elapsed;
715 tv.tv_sec = *timeout / 1000;
716 tv.tv_usec = (*timeout % 1000) * 1000;
725 } else if (ret == 0) {
741 Socket::Socket (int id)
742 : m_impl (new SocketImpl (id))
753 Socket::valid () const
755 return m_impl->valid ();
759 Socket::read (void *buf, size_t size) const
761 return m_impl->read (buf, size);
765 Socket::read_with_timeout (void *buf, size_t size, int timeout) const
767 return m_impl->read_with_timeout (buf, size, timeout);
771 Socket::write (const void *buf, size_t size) const
773 return m_impl->write (buf, size);
777 Socket::wait_for_data (int timeout) const
779 return m_impl->wait_for_data (timeout);
783 Socket::get_error_number () const
785 return m_impl->get_error_number ();
789 Socket::get_error_message () const
791 return m_impl->get_error_message ();
795 Socket::connect (const SocketAddress &addr) const
797 return m_impl->connect (addr);
801 Socket::bind (const SocketAddress &addr) const
803 return m_impl->bind (addr);
807 Socket::listen (int queue_length) const
809 return m_impl->listen (queue_length);
813 Socket::accept () const
815 return m_impl->accept ();
819 Socket::get_id () const
821 return m_impl->get_id ();
825 Socket::set_nonblock_mode ()
827 return m_impl->set_nonblock_mode ();
831 Socket::create (SocketFamily family)
833 return m_impl->create (family);
842 // Implementation of SocketServer
843 struct SocketServer::SocketServerImpl
853 std::vector <int> ext_fds;
855 SocketServerSignalSocket accept_signal;
856 SocketServerSignalSocket receive_signal;
857 SocketServerSignalSocket exception_signal;
859 SocketServerImpl (int mc)
860 : max_fd (0), err (0), running (false), created (false),
861 num_clients (0), max_clients (std::min (mc, SCIM_SOCKET_SERVER_MAX_CLIENTS)) {
862 FD_ZERO (&active_fds);
866 SocketServer::SocketServer (int max_clients)
867 : Socket (-1), m_impl (new SocketServerImpl (max_clients))
871 SocketServer::SocketServer (const SocketAddress &address, int max_clients)
872 : Socket (-1), m_impl (new SocketServerImpl (max_clients))
877 SocketServer::~SocketServer ()
883 SocketServer::valid () const
885 return m_impl->created;
889 SocketServer::create (const SocketAddress &address)
892 if (!m_impl->created) {
893 SocketFamily family = address.get_family ();
895 SCIM_DEBUG_SOCKET (1) << "Creating Socket Server, family: " << family << "\n";
897 if (family != SCIM_SOCKET_UNKNOWN) {
898 if (Socket::create (family) &&
899 Socket::bind (address) &&
901 m_impl->created = true;
902 m_impl->max_fd = Socket::get_id ();
903 FD_ZERO (&(m_impl->active_fds));
904 FD_SET (m_impl->max_fd, &(m_impl->active_fds));
908 m_impl->err = Socket::get_error_number ();
920 if (m_impl->created && !m_impl->running) {
921 fd_set read_fds, exception_fds;
925 m_impl->running = true;
928 read_fds = m_impl->active_fds;
929 exception_fds = m_impl->active_fds;
931 SCIM_DEBUG_SOCKET (2) << " SocketServer: Watching socket...\n";
933 if (select (m_impl->max_fd + 1, &read_fds, NULL, &exception_fds, NULL) < 0) {
938 m_impl->running = false;
939 SCIM_DEBUG_SOCKET (3) << " SocketServer: Error: "
940 << get_error_message () << "\n";
944 //The server has been shut down.
945 if (!m_impl->running)
948 for (i = 0; i<m_impl->max_fd + 1; i++) {
949 if (FD_ISSET (i, &read_fds)) {
952 if (i == Socket::get_id ()) {
953 client = Socket::accept ();
955 SCIM_DEBUG_SOCKET (3) << " SocketServer: Accept new connection:"
959 m_impl->err = Socket::get_error_number ();
960 m_impl->running = false;
962 SCIM_DEBUG_SOCKET (4) << " SocketServer: Error occurred: "
963 << Socket::get_error_message () << "\n";
968 if (m_impl->max_clients > 0 &&
969 m_impl->num_clients >= m_impl->max_clients) {
970 SCIM_DEBUG_SOCKET (4) << " SocketServer: Too many clients.\n";
973 m_impl->num_clients ++;
975 //Store the new client
976 FD_SET (client, &(m_impl->active_fds));
977 if (m_impl->max_fd < client)
978 m_impl->max_fd = client;
980 Socket client_socket (client);
982 m_impl->accept_signal.emit (this, client_socket);
987 SCIM_DEBUG_SOCKET (3) << " SocketServer: Accept client reading...\n";
989 Socket client_socket (i);
991 m_impl->receive_signal.emit (this, client_socket);
995 if (FD_ISSET (i, &exception_fds)) {
997 //The server got an exception, return.
998 if (i == Socket::get_id ()) {
1000 SCIM_DEBUG_SOCKET (3) << " SocketServer: Server got an exception, exiting...\n";
1006 SCIM_DEBUG_SOCKET (3) << " SocketServer: Client "
1008 << "got an exception, callbacking...\n";
1010 Socket client_socket (i);
1011 m_impl->exception_signal.emit (this, client_socket);
1015 if (!m_impl->running)
1019 //The server has been shut down.
1020 if (!m_impl->running)
1025 m_impl->err = EBADF;
1030 SocketServer::filter_event (int fd)
1033 static bool first_call = true;
1036 m_impl->running = true;
1040 if (fd == Socket::get_id ()) {
1041 client = Socket::accept ();
1043 SCIM_DEBUG_SOCKET (3) << " SocketServer: Accept new connection:"
1047 m_impl->err = Socket::get_error_number ();
1048 m_impl->running = false;
1050 SCIM_DEBUG_SOCKET (4) << " SocketServer: Error occurred: "
1051 << Socket::get_error_message () << "\n";
1056 if (m_impl->max_clients > 0 &&
1057 m_impl->num_clients >= m_impl->max_clients) {
1058 SCIM_DEBUG_SOCKET (4) << " SocketServer: Too many clients.\n";
1061 m_impl->num_clients ++;
1063 //Store the new client
1064 FD_SET (client, &(m_impl->active_fds));
1065 if (m_impl->max_fd < client)
1066 m_impl->max_fd = client;
1068 Socket client_socket (client);
1070 m_impl->accept_signal.emit (this, client_socket);
1073 SCIM_DEBUG_SOCKET (3) << " SocketServer: Accept client reading...\n";
1074 Socket client_socket (fd);
1075 m_impl->receive_signal.emit (this, client_socket);
1082 SocketServer::filter_exception_event (int fd)
1084 //The server got an exception, return.
1085 if (fd == Socket::get_id ()) {
1087 SCIM_DEBUG_SOCKET (3) << " SocketServer: Server got an exception, exiting...\n";
1091 SCIM_DEBUG_SOCKET (3) << " SocketServer: Client "
1093 << "got an exception, callbacking...\n";
1095 Socket client_socket (fd);
1096 m_impl->exception_signal.emit (this, client_socket);
1103 SocketServer::is_running () const
1105 return m_impl->running;
1109 SocketServer::shutdown ()
1111 if (m_impl->created) {
1112 SCIM_DEBUG_SOCKET (2) << " SocketServer: Shutting down the server...\n";
1114 m_impl->running = false;
1116 for (int i = 0; ((unsigned int)i) < m_impl->ext_fds.size (); i++)
1117 FD_CLR (m_impl->ext_fds [i], &m_impl->active_fds);
1119 for (int i = 0; i<m_impl->max_fd + 1; i++) {
1121 if (FD_ISSET (i, &(m_impl->active_fds)) && i != Socket::get_id ()) {
1122 SCIM_DEBUG_SOCKET (3) << " SocketServer: Closing client: "
1128 m_impl->created = false;
1130 m_impl->num_clients = 0;
1131 m_impl->ext_fds.clear ();
1132 FD_ZERO (&(m_impl->active_fds));
1139 SocketServer::close_connection (const Socket &socket)
1141 int id = socket.get_id ();
1142 if (m_impl->created && m_impl->running && id > 0 && FD_ISSET (id, &(m_impl->active_fds))) {
1144 SCIM_DEBUG_SOCKET (2) << " SocketServer: Closing the connection: " << id << "\n";
1146 m_impl->num_clients --;
1148 FD_CLR (id, &(m_impl->active_fds));
1150 std::vector <int>::iterator it = std::find (m_impl->ext_fds.begin (), m_impl->ext_fds.end (), id);
1151 if (it != m_impl->ext_fds.end ()) m_impl->ext_fds.erase (it);
1160 SocketServer::get_error_number () const
1165 return Socket::get_error_number ();
1169 SocketServer::get_error_message () const
1172 return String (strerror (m_impl->err));
1174 return Socket::get_error_message ();
1178 SocketServer::get_max_clients () const
1180 return m_impl->max_clients;
1184 SocketServer::set_max_clients (int max_clients)
1186 if (max_clients < SCIM_SOCKET_SERVER_MAX_CLIENTS)
1187 m_impl->max_clients = max_clients;
1191 SocketServer::insert_external_socket (const Socket &sock)
1193 int fd = sock.get_id ();
1195 if (valid () && sock.valid () && sock.wait_for_data (0) >= 0 &&
1196 m_impl->num_clients < m_impl->max_clients &&
1197 !FD_ISSET (fd, &m_impl->active_fds)) {
1198 m_impl->ext_fds.push_back (fd);
1199 FD_SET (fd, &m_impl->active_fds);
1200 if (m_impl->max_fd < fd) m_impl->max_fd = fd;
1201 m_impl->num_clients ++;
1208 SocketServer::remove_external_socket (const Socket &sock)
1210 int fd = sock.get_id ();
1212 if (valid () && FD_ISSET (fd, &m_impl->active_fds)) {
1213 FD_CLR (fd, &m_impl->active_fds);
1214 std::vector <int>::iterator it = std::find (m_impl->ext_fds.begin (), m_impl->ext_fds.end (), fd);
1215 if (it != m_impl->ext_fds.end ()) m_impl->ext_fds.erase (it);
1216 m_impl->num_clients --;
1223 SocketServer::signal_connect_accept (SocketServerSlotSocket *slot)
1225 return m_impl->accept_signal.connect (slot);
1229 SocketServer::signal_connect_receive (SocketServerSlotSocket *slot)
1231 return m_impl->receive_signal.connect (slot);
1235 SocketServer::signal_connect_exception (SocketServerSlotSocket *slot)
1237 return m_impl->exception_signal.connect (slot);
1240 //Implementation of SocketClient
1241 SocketClient::SocketClient ()
1242 : Socket (-1), m_connected (false)
1246 SocketClient::SocketClient (const SocketAddress &address)
1247 : Socket (-1), m_connected (false)
1252 SocketClient::~SocketClient ()
1257 SocketClient::is_connected () const
1259 return Socket::valid () && m_connected;
1263 SocketClient::connect (const SocketAddress &address)
1265 if (m_connected) close ();
1267 if (Socket::create (address.get_family ()) && Socket::connect (address)) {
1278 SocketClient::close ()
1281 m_connected = false;
1284 #define SCIM_DEFAULT_SOCKET_FRONTEND_ADDRESS "local:/tmp/scim-socket-frontend"
1285 #define SCIM_DEFAULT_PANEL_SOCKET_ADDRESS "local:/tmp/scim-panel-socket"
1286 #define SCIM_DEFAULT_HELPER_MANAGER_SOCKET_ADDRESS "local:/tmp/scim-socket-frontend"
1288 String scim_get_default_socket_frontend_address ()
1290 String address (SCIM_DEFAULT_SOCKET_FRONTEND_ADDRESS);
1292 address = scim_global_config_read (SCIM_GLOBAL_CONFIG_DEFAULT_SOCKET_FRONTEND_ADDRESS, address);
1294 const char *env = getenv ("SCIM_SOCKET_ADDRESS");
1295 if (env && strlen (env) > 0) {
1296 address = String (env);
1298 env = getenv ("SCIM_FRONTEND_SOCKET_ADDRESS");
1299 if (env && strlen (env))
1300 address = String (env);
1303 if (address == "default")
1304 address = SCIM_DEFAULT_SOCKET_FRONTEND_ADDRESS;
1309 String scim_get_default_socket_imengine_address ()
1311 String address (SCIM_DEFAULT_SOCKET_FRONTEND_ADDRESS);
1313 address = scim_global_config_read (SCIM_GLOBAL_CONFIG_DEFAULT_SOCKET_IMENGINE_ADDRESS, address);
1315 const char *env = getenv ("SCIM_SOCKET_ADDRESS");
1316 if (env && strlen (env) > 0) {
1317 address = String (env);
1319 env = getenv ("SCIM_IMENGINE_SOCKET_ADDRESS");
1320 if (env && strlen (env))
1321 address = String (env);
1324 if (address == "default")
1325 address = SCIM_DEFAULT_SOCKET_FRONTEND_ADDRESS;
1330 String scim_get_default_socket_config_address ()
1332 String address (SCIM_DEFAULT_SOCKET_FRONTEND_ADDRESS);
1334 address = scim_global_config_read (SCIM_GLOBAL_CONFIG_DEFAULT_SOCKET_CONFIG_ADDRESS, address);
1336 const char *env = getenv ("SCIM_SOCKET_ADDRESS");
1337 if (env && strlen (env) > 0) {
1338 address = String (env);
1340 env = getenv ("SCIM_CONFIG_SOCKET_ADDRESS");
1341 if (env && strlen (env))
1342 address = String (env);
1345 if (address == "default")
1346 address = SCIM_DEFAULT_SOCKET_FRONTEND_ADDRESS;
1351 String scim_get_default_panel_socket_address (const String &display)
1353 String address (SCIM_DEFAULT_PANEL_SOCKET_ADDRESS);
1355 address = scim_global_config_read (SCIM_GLOBAL_CONFIG_DEFAULT_PANEL_SOCKET_ADDRESS, address);
1357 const char *env = getenv ("SCIM_PANEL_SOCKET_ADDRESS");
1359 if (env && strlen (env) > 0) {
1360 address = String (env);
1363 if (address == "default")
1364 address = SCIM_DEFAULT_PANEL_SOCKET_ADDRESS;
1366 SocketAddress sockaddr (address);
1368 if (!sockaddr.valid ())
1371 String::size_type colon_pos = display.rfind (':');
1372 String disp_name = display;
1375 // Maybe It's a X11 DISPLAY name
1376 if (colon_pos != String::npos) {
1377 String::size_type dot_pos = display.find ('.', colon_pos+1);
1378 // It has screen number
1379 if (dot_pos != String::npos) {
1380 disp_name = display.substr (0, dot_pos);
1382 // FIXME: ignore remote X Server name.
1383 disp_num = atoi (display.substr (colon_pos + 1, dot_pos - colon_pos - 1).c_str ());
1386 if (sockaddr.get_family () == SCIM_SOCKET_LOCAL) {
1387 address = address + disp_name;
1388 } else if (sockaddr.get_family () == SCIM_SOCKET_INET) {
1389 std::vector <String> varlist;
1390 scim_split_string_list (varlist, address, ':');
1391 if (varlist.size () == 3) {
1392 int port = atoi (varlist [2].c_str ()) + disp_num;
1394 snprintf (buf, 10, "%d", port);
1395 varlist [2] = String (buf);
1396 address = scim_combine_string_list (varlist, ':');
1400 sockaddr.set_address (address);
1402 if (sockaddr.valid ())
1408 String scim_get_default_helper_manager_socket_address ()
1410 String address (SCIM_DEFAULT_HELPER_MANAGER_SOCKET_ADDRESS);
1412 address = scim_global_config_read (SCIM_GLOBAL_CONFIG_DEFAULT_HELPER_MANAGER_SOCKET_ADDRESS, address);
1414 const char *env = getenv ("SCIM_HELPER_MANAGER_SOCKET_ADDRESS");
1415 if (env && strlen (env) > 0) {
1416 address = String (env);
1419 if (address == "default")
1420 address = SCIM_DEFAULT_HELPER_MANAGER_SOCKET_ADDRESS;
1425 int scim_get_default_socket_timeout ()
1429 timeout = scim_global_config_read (SCIM_GLOBAL_CONFIG_DEFAULT_SOCKET_TIMEOUT, timeout);
1431 const char *env = getenv ("SCIM_SOCKET_TIMEOUT");
1433 if (env && strlen (env))
1434 timeout = atoi (env);
1436 if (timeout <= 0) timeout = -1;
1442 scim_socket_check_type (const String &types,
1443 const String &atype)
1445 std::vector <String> type_list;
1446 scim_split_string_list (type_list, types, ',');
1448 return std::find (type_list.begin (), type_list.end (), atype) != type_list.end ();
1452 scim_socket_open_connection (uint32 &key,
1453 const String &client_type,
1454 const String &server_type,
1455 const Socket &socket,
1458 if (!socket.valid () || !client_type.length () || !server_type.length ())
1463 trans.put_command (SCIM_TRANS_CMD_REQUEST);
1464 trans.put_command (SCIM_TRANS_CMD_OPEN_CONNECTION);
1465 trans.put_data (String (SCIM_BINARY_VERSION));
1466 trans.put_data (client_type);
1467 if (const_cast<Socket &>(socket).set_nonblock_mode () == -1)
1468 std::cerr << __func__ << "set_nonblock_mode () is failed!!!\n";
1469 if (trans.write_to_socket (socket)) {
1471 String server_types;
1472 if (trans.read_from_socket (socket, timeout) &&
1473 trans.get_command (cmd) && cmd == SCIM_TRANS_CMD_REPLY &&
1474 trans.get_data (server_types) && scim_socket_check_type (server_types, server_type) &&
1475 trans.get_data (key)) {
1477 trans.put_command (SCIM_TRANS_CMD_REPLY);
1478 trans.put_command (SCIM_TRANS_CMD_OK);
1479 if (trans.write_to_socket (socket))
1483 trans.put_command (SCIM_TRANS_CMD_REPLY);
1484 trans.put_command (SCIM_TRANS_CMD_FAIL);
1485 trans.write_to_socket (socket);
1493 scim_socket_accept_connection (uint32 &key,
1494 const String &server_types,
1495 const String &client_types,
1496 const Socket &socket,
1499 if (!socket.valid () || !client_types.length () || !server_types.length ())
1503 if (const_cast<Socket &>(socket).set_nonblock_mode () == -1)
1504 std::cerr << __func__ << "set_nonblock_mode () is failed!!!\n";
1505 if (trans.read_from_socket (socket, timeout)) {
1509 if (trans.get_command (cmd) && cmd == SCIM_TRANS_CMD_REQUEST &&
1510 trans.get_command (cmd) && cmd == SCIM_TRANS_CMD_OPEN_CONNECTION &&
1511 trans.get_data (version) && version == String (SCIM_BINARY_VERSION) &&
1512 trans.get_data (client_type) &&
1513 (scim_socket_check_type (client_types, client_type) || client_type == "ConnectionTester")) {
1514 key = (uint32) rand ();
1516 trans.put_command (SCIM_TRANS_CMD_REPLY);
1517 trans.put_data (server_types);
1518 trans.put_data (key);
1520 if (trans.write_to_socket (socket) &&
1521 trans.read_from_socket (socket, timeout) &&
1522 trans.get_command (cmd) && cmd == SCIM_TRANS_CMD_REPLY &&
1523 trans.get_command (cmd) && cmd == SCIM_TRANS_CMD_OK) {
1525 // Client is ok, return the client type.
1526 return (client_type == "ConnectionTester") ? String ("") : client_type;
1536 vi:ts=4:nowrap:ai:expandtab