PageRenderTime 52ms CodeModel.GetById 17ms RepoModel.GetById 0ms app.codeStats 0ms

/src/socket.c

https://github.com/cmcl/geany
C | 809 lines | 586 code | 133 blank | 90 comment | 119 complexity | fb7c61e300b3e81ff90bf4da4bd74e6a MD5 | raw file
Possible License(s): GPL-2.0, BSD-3-Clause
  1. /*
  2. * socket.c - this file is part of Geany, a fast and lightweight IDE
  3. *
  4. * Copyright 2006-2012 Enrico Trรถger <enrico(dot)troeger(at)uvena(dot)de>
  5. * Copyright 2006-2012 Nick Treleaven <nick(dot)treleaven(at)btinternet(dot)com>
  6. * Copyright 2006 Hiroyuki Yamamoto (author of Sylpheed)
  7. *
  8. * This program is free software; you can redistribute it and/or modify
  9. * it under the terms of the GNU General Public License as published by
  10. * the Free Software Foundation; either version 2 of the License, or
  11. * (at your option) any later version.
  12. *
  13. * This program is distributed in the hope that it will be useful,
  14. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  15. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  16. * GNU General Public License for more details.
  17. *
  18. * You should have received a copy of the GNU General Public License along
  19. * with this program; if not, write to the Free Software Foundation, Inc.,
  20. * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  21. */
  22. /*
  23. * Socket setup and messages handling.
  24. * The socket allows detection and messages to be sent to the first running instance of Geany.
  25. * Only the first instance loads session files at startup, and opens files from the command-line.
  26. */
  27. /*
  28. * Little dev doc:
  29. * Each command which is sent between two instances (see send_open_command and
  30. * socket_lock_input_cb) should have the following scheme:
  31. * command name\n
  32. * data\n
  33. * data\n
  34. * ...
  35. * .\n
  36. * The first thing should be the command name followed by the data belonging to the command and
  37. * to mark the end of data send a single '.'. Each message should be ended with \n.
  38. * The command window is only available on Windows and takes no additional data, instead it
  39. * writes back a Windows handle (HWND) for the main window to set it to the foreground (focus).
  40. *
  41. * At the moment the commands window, doclist, open, openro, line and column are available.
  42. *
  43. * About the socket files on Unix-like systems:
  44. * Geany creates a socket in /tmp (or any other directory returned by g_get_tmp_dir()) and
  45. * a symlink in the current configuration to the created socket file. The symlink is named
  46. * geany_socket_<hostname>_<displayname> (displayname is the name of the active X display).
  47. * If the socket file cannot be created in the temporary directory, Geany creates the socket file
  48. * directly in the configuration directory as a fallback.
  49. *
  50. */
  51. #include "geany.h"
  52. #ifdef HAVE_SOCKET
  53. #ifndef G_OS_WIN32
  54. # include <sys/time.h>
  55. # include <sys/types.h>
  56. # include <sys/socket.h>
  57. # include <sys/un.h>
  58. # include <netinet/in.h>
  59. # include <glib/gstdio.h>
  60. #else
  61. # include <gdk/gdkwin32.h>
  62. # include <windows.h>
  63. # include <winsock2.h>
  64. # include <ws2tcpip.h>
  65. #endif
  66. #include <string.h>
  67. #include <stdlib.h>
  68. #include <unistd.h>
  69. #include <fcntl.h>
  70. #ifdef GDK_WINDOWING_X11
  71. #include <gdk/gdkx.h>
  72. #endif
  73. #include "main.h"
  74. #include "socket.h"
  75. #include "document.h"
  76. #include "support.h"
  77. #include "ui_utils.h"
  78. #include "utils.h"
  79. #include "dialogs.h"
  80. #include "encodings.h"
  81. #include "project.h"
  82. #ifdef G_OS_WIN32
  83. #define REMOTE_CMD_PORT 49876
  84. #define SOCKET_IS_VALID(s) ((s) != INVALID_SOCKET)
  85. #else
  86. #define SOCKET_IS_VALID(s) ((s) >= 0)
  87. #define INVALID_SOCKET (-1)
  88. #endif
  89. #define BUFFER_LENGTH 4096
  90. struct socket_info_struct socket_info;
  91. #ifdef G_OS_WIN32
  92. static gint socket_fd_connect_inet (gushort port);
  93. static gint socket_fd_open_inet (gushort port);
  94. static void socket_init_win32 (void);
  95. #else
  96. static gint socket_fd_connect_unix (const gchar *path);
  97. static gint socket_fd_open_unix (const gchar *path);
  98. #endif
  99. static gint socket_fd_write (gint sock, const gchar *buf, gint len);
  100. static gint socket_fd_write_all (gint sock, const gchar *buf, gint len);
  101. static gint socket_fd_gets (gint sock, gchar *buf, gint len);
  102. static gint socket_fd_check_io (gint fd, GIOCondition cond);
  103. static gint socket_fd_read (gint sock, gchar *buf, gint len);
  104. static gint socket_fd_recv (gint fd, gchar *buf, gint len, gint flags);
  105. static gint socket_fd_close (gint sock);
  106. static void send_open_command(gint sock, gint argc, gchar **argv)
  107. {
  108. gint i;
  109. gchar *filename;
  110. g_return_if_fail(argc > 1);
  111. geany_debug("using running instance of Geany");
  112. if (cl_options.goto_line >= 0)
  113. {
  114. gchar *line = g_strdup_printf("%d\n", cl_options.goto_line);
  115. socket_fd_write_all(sock, "line\n", 5);
  116. socket_fd_write_all(sock, line, strlen(line));
  117. socket_fd_write_all(sock, ".\n", 2);
  118. g_free(line);
  119. }
  120. if (cl_options.goto_column >= 0)
  121. {
  122. gchar *col = g_strdup_printf("%d\n", cl_options.goto_column);
  123. socket_fd_write_all(sock, "column\n", 7);
  124. socket_fd_write_all(sock, col, strlen(col));
  125. socket_fd_write_all(sock, ".\n", 2);
  126. g_free(col);
  127. }
  128. if (cl_options.readonly) /* append "ro" to denote readonly status for new docs */
  129. socket_fd_write_all(sock, "openro\n", 7);
  130. else
  131. socket_fd_write_all(sock, "open\n", 5);
  132. for (i = 1; i < argc && argv[i] != NULL; i++)
  133. {
  134. filename = main_get_argv_filename(argv[i]);
  135. /* if the filename is valid or if a new file should be opened is check on the other side */
  136. if (filename != NULL)
  137. {
  138. socket_fd_write_all(sock, filename, strlen(filename));
  139. socket_fd_write_all(sock, "\n", 1);
  140. }
  141. else
  142. {
  143. g_printerr(_("Could not find file '%s'."), filename);
  144. g_printerr("\n"); /* keep translation from open_cl_files() in main.c. */
  145. }
  146. g_free(filename);
  147. }
  148. socket_fd_write_all(sock, ".\n", 2);
  149. }
  150. #ifndef G_OS_WIN32
  151. static void remove_socket_link_full(void)
  152. {
  153. gchar real_path[512];
  154. gsize len;
  155. real_path[0] = '\0';
  156. /* read the contents of the symbolic link socket_info.file_name and delete it
  157. * readlink should return something like "/tmp/geany_socket.499602d2" */
  158. len = readlink(socket_info.file_name, real_path, sizeof(real_path) - 1);
  159. if ((gint) len > 0)
  160. {
  161. real_path[len] = '\0';
  162. g_unlink(real_path);
  163. }
  164. g_unlink(socket_info.file_name);
  165. }
  166. #endif
  167. static void socket_get_document_list(gint sock)
  168. {
  169. gchar doc_list[BUFFER_LENGTH];
  170. gint doc_list_len;
  171. if (sock < 0)
  172. return;
  173. socket_fd_write_all(sock, "doclist\n", 8);
  174. doc_list_len = socket_fd_read(sock, doc_list, sizeof(doc_list));
  175. if (doc_list_len >= BUFFER_LENGTH)
  176. doc_list_len = BUFFER_LENGTH -1;
  177. doc_list[doc_list_len] = '\0';
  178. /* if we received ETX (end-of-text), there were no open files, so print only otherwise */
  179. if (! utils_str_equal(doc_list, "\3"))
  180. printf("%s", doc_list);
  181. }
  182. #ifndef G_OS_WIN32
  183. static void check_socket_permissions(void)
  184. {
  185. struct stat socket_stat;
  186. if (g_lstat(socket_info.file_name, &socket_stat) == 0)
  187. { /* If the user id of the process is not the same as the owner of the socket
  188. * file, then ignore this socket and start a new session. */
  189. if (socket_stat.st_uid != getuid())
  190. {
  191. const gchar *msg = _(
  192. /* TODO maybe this message needs a rewording */
  193. "Geany tried to access the Unix Domain socket of another instance running as another user.\n"
  194. "This is a fatal error and Geany will now quit.");
  195. g_warning("%s", msg);
  196. dialogs_show_msgbox(GTK_MESSAGE_ERROR, "%s", msg);
  197. exit(1);
  198. }
  199. }
  200. }
  201. #endif
  202. /* (Unix domain) socket support to replace the old FIFO code
  203. * (taken from Sylpheed, thanks)
  204. * Returns the created socket, -1 if an error occurred or -2 if another socket exists and files
  205. * were sent to it. */
  206. gint socket_init(gint argc, gchar **argv)
  207. {
  208. gint sock;
  209. #ifdef G_OS_WIN32
  210. HANDLE hmutex;
  211. HWND hwnd;
  212. socket_init_win32();
  213. hmutex = CreateMutexA(NULL, FALSE, "Geany");
  214. if (! hmutex)
  215. {
  216. geany_debug("cannot create Mutex\n");
  217. return -1;
  218. }
  219. if (GetLastError() != ERROR_ALREADY_EXISTS)
  220. {
  221. /* To support multiple instances with different configuration directories (as we do on
  222. * non-Windows systems) we would need to use different port number s but it might be
  223. * difficult to get a port number which is unique for a configuration directory (path)
  224. * and which is unused. This port number has to be guessed by the first and new instance
  225. * and the only data is the configuration directory path.
  226. * For now we use one port number, that is we support only one instance at all. */
  227. sock = socket_fd_open_inet(REMOTE_CMD_PORT);
  228. if (sock < 0)
  229. return 0;
  230. return sock;
  231. }
  232. sock = socket_fd_connect_inet(REMOTE_CMD_PORT);
  233. if (sock < 0)
  234. return -1;
  235. #else
  236. gchar *display_name = gdk_get_display();
  237. gchar *hostname = utils_get_hostname();
  238. gchar *p;
  239. if (display_name == NULL)
  240. display_name = g_strdup("NODISPLAY");
  241. /* these lines are taken from dcopc.c in kdelibs */
  242. if ((p = strrchr(display_name, '.')) > strrchr(display_name, ':') && p != NULL)
  243. *p = '\0';
  244. /* remove characters that may not be acceptable in a filename */
  245. for (p = display_name; *p; p++)
  246. {
  247. if (*p == ':' || *p == '/')
  248. *p = '_';
  249. }
  250. if (socket_info.file_name == NULL)
  251. socket_info.file_name = g_strdup_printf("%s%cgeany_socket_%s_%s",
  252. app->configdir, G_DIR_SEPARATOR, hostname, display_name);
  253. g_free(display_name);
  254. g_free(hostname);
  255. /* check whether the real user id is the same as this of the socket file */
  256. check_socket_permissions();
  257. sock = socket_fd_connect_unix(socket_info.file_name);
  258. if (sock < 0)
  259. {
  260. remove_socket_link_full(); /* deletes the socket file and the symlink */
  261. return socket_fd_open_unix(socket_info.file_name);
  262. }
  263. #endif
  264. /* remote command mode, here we have another running instance and want to use it */
  265. #ifdef G_OS_WIN32
  266. /* first we send a request to retrieve the window handle and focus the window */
  267. socket_fd_write_all(sock, "window\n", 7);
  268. if (socket_fd_read(sock, (gchar *)&hwnd, sizeof(hwnd)) == sizeof(hwnd))
  269. SetForegroundWindow(hwnd);
  270. #endif
  271. /* now we send the command line args */
  272. if (argc > 1)
  273. {
  274. send_open_command(sock, argc, argv);
  275. }
  276. if (cl_options.list_documents)
  277. {
  278. socket_get_document_list(sock);
  279. }
  280. socket_fd_close(sock);
  281. return -2;
  282. }
  283. gint socket_finalize(void)
  284. {
  285. if (socket_info.lock_socket < 0)
  286. return -1;
  287. if (socket_info.lock_socket_tag > 0)
  288. g_source_remove(socket_info.lock_socket_tag);
  289. if (socket_info.read_ioc)
  290. {
  291. g_io_channel_shutdown(socket_info.read_ioc, FALSE, NULL);
  292. g_io_channel_unref(socket_info.read_ioc);
  293. socket_info.read_ioc = NULL;
  294. }
  295. #ifdef G_OS_WIN32
  296. WSACleanup();
  297. #else
  298. if (socket_info.file_name != NULL)
  299. {
  300. remove_socket_link_full(); /* deletes the socket file and the symlink */
  301. g_free(socket_info.file_name);
  302. }
  303. #endif
  304. return 0;
  305. }
  306. #ifdef G_OS_UNIX
  307. static gint socket_fd_connect_unix(const gchar *path)
  308. {
  309. gint sock;
  310. struct sockaddr_un addr;
  311. sock = socket(PF_UNIX, SOCK_STREAM, 0);
  312. if (sock < 0)
  313. {
  314. perror("fd_connect_unix(): socket");
  315. return -1;
  316. }
  317. memset(&addr, 0, sizeof(addr));
  318. addr.sun_family = AF_UNIX;
  319. strncpy(addr.sun_path, path, sizeof(addr.sun_path) - 1);
  320. if (connect(sock, (struct sockaddr *)&addr, sizeof(addr)) < 0)
  321. {
  322. socket_fd_close(sock);
  323. return -1;
  324. }
  325. return sock;
  326. }
  327. static gint socket_fd_open_unix(const gchar *path)
  328. {
  329. gint sock;
  330. struct sockaddr_un addr;
  331. gint val;
  332. gchar *real_path;
  333. sock = socket(PF_UNIX, SOCK_STREAM, 0);
  334. if (sock < 0)
  335. {
  336. perror("sock_open_unix(): socket");
  337. return -1;
  338. }
  339. val = 1;
  340. if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &val, sizeof(val)) < 0)
  341. {
  342. perror("setsockopt");
  343. socket_fd_close(sock);
  344. return -1;
  345. }
  346. /* fix for #1888561:
  347. * in case the configuration directory is located on a network file system or any other
  348. * file system which doesn't support sockets, we just link the socket there and create the
  349. * real socket in the system's tmp directory assuming it supports sockets */
  350. real_path = g_strdup_printf("%s%cgeany_socket.%08x",
  351. g_get_tmp_dir(), G_DIR_SEPARATOR, g_random_int());
  352. if (utils_is_file_writable(real_path) != 0)
  353. { /* if real_path is not writable for us, fall back to ~/.config/geany/geany_socket_*_* */
  354. /* instead of creating a symlink and print a warning */
  355. g_warning("Socket %s could not be written, using %s as fallback.", real_path, path);
  356. SETPTR(real_path, g_strdup(path));
  357. }
  358. /* create a symlink in e.g. ~/.config/geany/geany_socket_hostname__0 to /tmp/geany_socket.499602d2 */
  359. else if (symlink(real_path, path) != 0)
  360. {
  361. perror("symlink");
  362. socket_fd_close(sock);
  363. return -1;
  364. }
  365. memset(&addr, 0, sizeof(addr));
  366. addr.sun_family = AF_UNIX;
  367. strncpy(addr.sun_path, real_path, sizeof(addr.sun_path) - 1);
  368. if (bind(sock, (struct sockaddr *)&addr, sizeof(addr)) < 0)
  369. {
  370. perror("bind");
  371. socket_fd_close(sock);
  372. return -1;
  373. }
  374. if (listen(sock, 1) < 0)
  375. {
  376. perror("listen");
  377. socket_fd_close(sock);
  378. return -1;
  379. }
  380. g_chmod(real_path, 0600);
  381. g_free(real_path);
  382. return sock;
  383. }
  384. #endif
  385. static gint socket_fd_close(gint fd)
  386. {
  387. #ifdef G_OS_WIN32
  388. return closesocket(fd);
  389. #else
  390. return close(fd);
  391. #endif
  392. }
  393. #ifdef G_OS_WIN32
  394. static gint socket_fd_open_inet(gushort port)
  395. {
  396. SOCKET sock;
  397. struct sockaddr_in addr;
  398. gchar val;
  399. sock = socket(AF_INET, SOCK_STREAM, 0);
  400. if (G_UNLIKELY(! SOCKET_IS_VALID(sock)))
  401. {
  402. geany_debug("fd_open_inet(): socket() failed: %d\n", WSAGetLastError());
  403. return -1;
  404. }
  405. val = 1;
  406. if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &val, sizeof(val)) < 0)
  407. {
  408. perror("setsockopt");
  409. socket_fd_close(sock);
  410. return -1;
  411. }
  412. memset(&addr, 0, sizeof(addr));
  413. addr.sin_family = AF_INET;
  414. addr.sin_port = htons(port);
  415. addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
  416. if (bind(sock, (struct sockaddr *)&addr, sizeof(addr)) < 0)
  417. {
  418. perror("bind");
  419. socket_fd_close(sock);
  420. return -1;
  421. }
  422. if (listen(sock, 1) < 0)
  423. {
  424. perror("listen");
  425. socket_fd_close(sock);
  426. return -1;
  427. }
  428. return sock;
  429. }
  430. static gint socket_fd_connect_inet(gushort port)
  431. {
  432. SOCKET sock;
  433. struct sockaddr_in addr;
  434. sock = socket(AF_INET, SOCK_STREAM, 0);
  435. if (G_UNLIKELY(! SOCKET_IS_VALID(sock)))
  436. {
  437. geany_debug("fd_connect_inet(): socket() failed: %d\n", WSAGetLastError());
  438. return -1;
  439. }
  440. memset(&addr, 0, sizeof(addr));
  441. addr.sin_family = AF_INET;
  442. addr.sin_port = htons(port);
  443. addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
  444. if (connect(sock, (struct sockaddr *)&addr, sizeof(addr)) < 0)
  445. {
  446. socket_fd_close(sock);
  447. return -1;
  448. }
  449. return sock;
  450. }
  451. static void socket_init_win32(void)
  452. {
  453. WSADATA wsadata;
  454. if (WSAStartup(MAKEWORD(2, 2), &wsadata) != NO_ERROR)
  455. geany_debug("WSAStartup() failed\n");
  456. return;
  457. }
  458. #endif
  459. static void handle_input_filename(const gchar *buf)
  460. {
  461. gchar *utf8_filename, *locale_filename;
  462. /* we never know how the input is encoded, so do the best auto detection we can */
  463. if (! g_utf8_validate(buf, -1, NULL))
  464. utf8_filename = encodings_convert_to_utf8(buf, -1, NULL);
  465. else
  466. utf8_filename = g_strdup(buf);
  467. locale_filename = utils_get_locale_from_utf8(utf8_filename);
  468. if (locale_filename)
  469. {
  470. if (g_str_has_suffix(locale_filename, ".geany"))
  471. {
  472. if (project_ask_close())
  473. main_load_project_from_command_line(locale_filename, TRUE);
  474. }
  475. else
  476. main_handle_filename(locale_filename);
  477. }
  478. g_free(utf8_filename);
  479. g_free(locale_filename);
  480. }
  481. static gchar *build_document_list(void)
  482. {
  483. GString *doc_list = g_string_new(NULL);
  484. guint i;
  485. const gchar *filename;
  486. foreach_document(i)
  487. {
  488. filename = DOC_FILENAME(documents[i]);
  489. g_string_append(doc_list, filename);
  490. g_string_append_c(doc_list, '\n');
  491. }
  492. return g_string_free(doc_list, FALSE);
  493. }
  494. gboolean socket_lock_input_cb(GIOChannel *source, GIOCondition condition, gpointer data)
  495. {
  496. gint fd, sock;
  497. gchar buf[BUFFER_LENGTH];
  498. struct sockaddr_in caddr;
  499. socklen_t caddr_len = sizeof(caddr);
  500. GtkWidget *window = data;
  501. gboolean popup = FALSE;
  502. fd = g_io_channel_unix_get_fd(source);
  503. sock = accept(fd, (struct sockaddr *)&caddr, &caddr_len);
  504. /* first get the command */
  505. while (socket_fd_gets(sock, buf, sizeof(buf)) != -1)
  506. {
  507. if (strncmp(buf, "open", 4) == 0)
  508. {
  509. cl_options.readonly = strncmp(buf+4, "ro", 2) == 0; /* open in readonly? */
  510. while (socket_fd_gets(sock, buf, sizeof(buf)) != -1 && *buf != '.')
  511. {
  512. gsize buf_len = strlen(buf);
  513. /* remove trailing newline */
  514. if (buf_len > 0 && buf[buf_len - 1] == '\n')
  515. buf[buf_len - 1] = '\0';
  516. handle_input_filename(buf);
  517. }
  518. popup = TRUE;
  519. }
  520. else if (strncmp(buf, "doclist", 7) == 0)
  521. {
  522. gchar *doc_list = build_document_list();
  523. if (NZV(doc_list))
  524. socket_fd_write_all(sock, doc_list, strlen(doc_list));
  525. else
  526. /* send ETX (end-of-text) in case we have no open files, we must send anything
  527. * otherwise the client would hang on reading */
  528. socket_fd_write_all(sock, "\3", 1);
  529. g_free(doc_list);
  530. }
  531. else if (strncmp(buf, "line", 4) == 0)
  532. {
  533. while (socket_fd_gets(sock, buf, sizeof(buf)) != -1 && *buf != '.')
  534. {
  535. g_strstrip(buf); /* remove \n char */
  536. /* on any error we get 0 which should be safe enough as fallback */
  537. cl_options.goto_line = atoi(buf);
  538. }
  539. }
  540. else if (strncmp(buf, "column", 6) == 0)
  541. {
  542. while (socket_fd_gets(sock, buf, sizeof(buf)) != -1 && *buf != '.')
  543. {
  544. g_strstrip(buf); /* remove \n char */
  545. /* on any error we get 0 which should be safe enough as fallback */
  546. cl_options.goto_column = atoi(buf);
  547. }
  548. }
  549. #ifdef G_OS_WIN32
  550. else if (strncmp(buf, "window", 6) == 0)
  551. {
  552. HWND hwnd = (HWND) gdk_win32_drawable_get_handle(
  553. GDK_DRAWABLE(gtk_widget_get_window(window)));
  554. socket_fd_write(sock, (gchar *)&hwnd, sizeof(hwnd));
  555. }
  556. #endif
  557. }
  558. if (popup)
  559. {
  560. #ifdef GDK_WINDOWING_X11
  561. /* Set the proper interaction time on the window. This seems necessary to make
  562. * gtk_window_present() really bring the main window into the foreground on some
  563. * window managers like Gnome's metacity.
  564. * Code taken from Gedit. */
  565. gdk_x11_window_set_user_time(gtk_widget_get_window(window),
  566. gdk_x11_get_server_time(gtk_widget_get_window(window)));
  567. #endif
  568. gtk_window_present(GTK_WINDOW(window));
  569. #ifdef G_OS_WIN32
  570. gdk_window_show(gtk_widget_get_window(window));
  571. #endif
  572. }
  573. socket_fd_close(sock);
  574. return TRUE;
  575. }
  576. static gint socket_fd_gets(gint fd, gchar *buf, gint len)
  577. {
  578. gchar *newline, *bp = buf;
  579. gint n;
  580. if (--len < 1)
  581. return -1;
  582. do
  583. {
  584. if ((n = socket_fd_recv(fd, bp, len, MSG_PEEK)) <= 0)
  585. return -1;
  586. if ((newline = memchr(bp, '\n', n)) != NULL)
  587. n = newline - bp + 1;
  588. if ((n = socket_fd_read(fd, bp, n)) < 0)
  589. return -1;
  590. bp += n;
  591. len -= n;
  592. } while (! newline && len);
  593. *bp = '\0';
  594. return bp - buf;
  595. }
  596. static gint socket_fd_recv(gint fd, gchar *buf, gint len, gint flags)
  597. {
  598. if (socket_fd_check_io(fd, G_IO_IN) < 0)
  599. return -1;
  600. return recv(fd, buf, len, flags);
  601. }
  602. static gint socket_fd_read(gint fd, gchar *buf, gint len)
  603. {
  604. if (socket_fd_check_io(fd, G_IO_IN) < 0)
  605. return -1;
  606. #ifdef G_OS_WIN32
  607. return recv(fd, buf, len, 0);
  608. #else
  609. return read(fd, buf, len);
  610. #endif
  611. }
  612. static gint socket_fd_check_io(gint fd, GIOCondition cond)
  613. {
  614. struct timeval timeout;
  615. fd_set fds;
  616. #ifdef G_OS_UNIX
  617. gint flags;
  618. #endif
  619. timeout.tv_sec = 60;
  620. timeout.tv_usec = 0;
  621. #ifdef G_OS_UNIX
  622. /* checking for non-blocking mode */
  623. flags = fcntl(fd, F_GETFL, 0);
  624. if (flags < 0)
  625. {
  626. perror("fcntl");
  627. return 0;
  628. }
  629. if ((flags & O_NONBLOCK) != 0)
  630. return 0;
  631. #endif
  632. FD_ZERO(&fds);
  633. FD_SET(fd, &fds);
  634. if (cond == G_IO_IN)
  635. {
  636. select(fd + 1, &fds, NULL, NULL, &timeout);
  637. }
  638. else
  639. {
  640. select(fd + 1, NULL, &fds, NULL, &timeout);
  641. }
  642. if (FD_ISSET(fd, &fds))
  643. {
  644. return 0;
  645. }
  646. else
  647. {
  648. geany_debug("Socket IO timeout");
  649. return -1;
  650. }
  651. }
  652. static gint socket_fd_write_all(gint fd, const gchar *buf, gint len)
  653. {
  654. gint n, wrlen = 0;
  655. while (len)
  656. {
  657. n = socket_fd_write(fd, buf, len);
  658. if (n <= 0)
  659. return -1;
  660. len -= n;
  661. wrlen += n;
  662. buf += n;
  663. }
  664. return wrlen;
  665. }
  666. gint socket_fd_write(gint fd, const gchar *buf, gint len)
  667. {
  668. if (socket_fd_check_io(fd, G_IO_OUT) < 0)
  669. return -1;
  670. #ifdef G_OS_WIN32
  671. return send(fd, buf, len, 0);
  672. #else
  673. return write(fd, buf, len);
  674. #endif
  675. }
  676. #endif