PageRenderTime 57ms CodeModel.GetById 25ms RepoModel.GetById 1ms app.codeStats 0ms

/src/socket.c

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