blob: 416b5381556482c32ef4ae673f0df2f3dacedc2b [file] [log] [blame]
Bram Moolenaare0874f82016-01-24 20:36:41 +01001/* vi:set ts=8 sts=4 sw=4:
2 *
3 * VIM - Vi IMproved by Bram Moolenaar
4 *
5 * Do ":help uganda" in Vim to read copying and usage conditions.
6 * Do ":help credits" in Vim to see a list of people who contributed.
7 */
8
9/*
10 * Implements communication through a socket or any file handle.
11 */
12
13#include "vim.h"
14
15#if defined(FEAT_CHANNEL) || defined(PROTO)
16
Bram Moolenaard04a0202016-01-26 23:30:18 +010017/*
18 * Change the zero to 1 to enable debugging.
19 * This will write a file "channel_debug.log".
20 */
21#if 0
22# define CHERROR(fmt, arg) cherror(fmt, arg)
23# define CHLOG(idx, send, buf) chlog(idx, send, buf)
24# define CHFILE "channel_debug.log"
25
26static void cherror(char *fmt, char *arg);
27static void chlog(int send, char_u *buf);
28#else
29# define CHERROR(fmt, arg)
30# define CHLOG(idx, send, buf)
31#endif
32
33/* TRUE when netbeans is running with a GUI. */
34#ifdef FEAT_GUI
35# define CH_HAS_GUI (gui.in_use || gui.starting)
36#endif
37
38/* Note: when making changes here also adjust configure.in. */
39#ifdef WIN32
40/* WinSock API is separated from C API, thus we can't use read(), write(),
41 * errno... */
42# define SOCK_ERRNO errno = WSAGetLastError()
43# undef ECONNREFUSED
44# define ECONNREFUSED WSAECONNREFUSED
45# ifdef EINTR
46# undef EINTR
47# endif
48# define EINTR WSAEINTR
49# define sock_write(sd, buf, len) send(sd, buf, len, 0)
50# define sock_read(sd, buf, len) recv(sd, buf, len, 0)
51# define sock_close(sd) closesocket(sd)
52# define sleep(t) Sleep(t*1000) /* WinAPI Sleep() accepts milliseconds */
53#else
54# include <netdb.h>
55# include <netinet/in.h>
56
57# include <sys/socket.h>
58# ifdef HAVE_LIBGEN_H
59# include <libgen.h>
60# endif
61# define SOCK_ERRNO
62# define sock_write(sd, buf, len) write(sd, buf, len)
63# define sock_read(sd, buf, len) read(sd, buf, len)
64# define sock_close(sd) close(sd)
65#endif
66
67#ifdef FEAT_GUI_W32
68extern HWND s_hwnd; /* Gvim's Window handle */
69#endif
70
71struct readqueue
72{
73 char_u *buffer;
74 struct readqueue *next;
75 struct readqueue *prev;
76};
77typedef struct readqueue queue_T;
78
Bram Moolenaare0874f82016-01-24 20:36:41 +010079typedef struct {
Bram Moolenaar3b5f9292016-01-28 22:37:01 +010080 sock_T ch_fd; /* the socket, -1 for a closed channel */
81 int ch_idx; /* used by channel_poll_setup() */
82 queue_T ch_head; /* dummy node, header for circular queue */
Bram Moolenaard04a0202016-01-26 23:30:18 +010083
Bram Moolenaar3b5f9292016-01-28 22:37:01 +010084 int ch_error; /* When TRUE an error was reported. Avoids giving
Bram Moolenaard04a0202016-01-26 23:30:18 +010085 * pages full of error messages when the other side
86 * has exited, only mention the first error until the
87 * connection works again. */
88#ifdef FEAT_GUI_X11
89 XtInputId ch_inputHandler; /* Cookie for input */
90#endif
91#ifdef FEAT_GUI_GTK
Bram Moolenaar3b5f9292016-01-28 22:37:01 +010092 gint ch_inputHandler; /* Cookie for input */
Bram Moolenaard04a0202016-01-26 23:30:18 +010093#endif
Bram Moolenaarf12d9832016-01-29 21:11:25 +010094#ifdef WIN32
Bram Moolenaar3b5f9292016-01-28 22:37:01 +010095 int ch_inputHandler; /* simply ret.value of WSAAsyncSelect() */
Bram Moolenaard04a0202016-01-26 23:30:18 +010096#endif
97
Bram Moolenaar3b5f9292016-01-28 22:37:01 +010098 void (*ch_close_cb)(void); /* callback for when channel is closed */
99
100 char_u *ch_callback; /* function to call when a msg is not handled */
101 char_u *ch_req_callback; /* function to call for current request */
Bram Moolenaar3b5f9292016-01-28 22:37:01 +0100102
103 int ch_json_mode;
Bram Moolenaare0874f82016-01-24 20:36:41 +0100104} channel_T;
105
Bram Moolenaard04a0202016-01-26 23:30:18 +0100106/*
107 * Information about all channels.
108 * There can be gaps for closed channels, they will be reused later.
109 */
Bram Moolenaare0874f82016-01-24 20:36:41 +0100110static channel_T *channels = NULL;
111static int channel_count = 0;
112
113/*
Bram Moolenaard04a0202016-01-26 23:30:18 +0100114 * TODO: open debug file when desired.
115 */
116FILE *debugfd = NULL;
117
118/*
Bram Moolenaare0874f82016-01-24 20:36:41 +0100119 * Add a new channel slot, return the index.
Bram Moolenaard04a0202016-01-26 23:30:18 +0100120 * The channel isn't actually used into ch_fd is set >= 0;
121 * Returns -1 if all channels are in use.
Bram Moolenaare0874f82016-01-24 20:36:41 +0100122 */
123 static int
124add_channel(void)
125{
126 int idx;
127 channel_T *new_channels;
128
129 if (channels != NULL)
130 for (idx = 0; idx < channel_count; ++idx)
131 if (channels[idx].ch_fd < 0)
132 /* re-use a closed channel slot */
133 return idx;
134 if (channel_count == MAX_OPEN_CHANNELS)
135 return -1;
Bram Moolenaard04a0202016-01-26 23:30:18 +0100136 new_channels = (channel_T *)alloc(sizeof(channel_T) * (channel_count + 1));
Bram Moolenaare0874f82016-01-24 20:36:41 +0100137 if (new_channels == NULL)
138 return -1;
139 if (channels != NULL)
140 mch_memmove(new_channels, channels, sizeof(channel_T) * channel_count);
141 channels = new_channels;
Bram Moolenaard04a0202016-01-26 23:30:18 +0100142 (void)vim_memset(&channels[channel_count], 0, sizeof(channel_T));
143
Bram Moolenaare0874f82016-01-24 20:36:41 +0100144 channels[channel_count].ch_fd = (sock_T)-1;
Bram Moolenaard04a0202016-01-26 23:30:18 +0100145#ifdef FEAT_GUI_X11
146 channels[channel_count].ch_inputHandler = (XtInputId)NULL;
147#endif
148#ifdef FEAT_GUI_GTK
149 channels[channel_count].ch_inputHandler = 0;
150#endif
151#ifdef FEAT_GUI_W32
152 channels[channel_count].ch_inputHandler = -1;
153#endif
Bram Moolenaare0874f82016-01-24 20:36:41 +0100154
155 return channel_count++;
156}
157
Bram Moolenaard04a0202016-01-26 23:30:18 +0100158#if defined(FEAT_GUI) || defined(PROTO)
Bram Moolenaare0874f82016-01-24 20:36:41 +0100159/*
Bram Moolenaard04a0202016-01-26 23:30:18 +0100160 * Read a command from netbeans.
Bram Moolenaare0874f82016-01-24 20:36:41 +0100161 */
Bram Moolenaard04a0202016-01-26 23:30:18 +0100162#ifdef FEAT_GUI_X11
163 static void
164messageFromNetbeans(XtPointer clientData,
165 int *unused1 UNUSED,
166 XtInputId *unused2 UNUSED)
Bram Moolenaare0874f82016-01-24 20:36:41 +0100167{
Bram Moolenaard04a0202016-01-26 23:30:18 +0100168 channel_read((int)(long)clientData);
Bram Moolenaare0874f82016-01-24 20:36:41 +0100169}
Bram Moolenaard04a0202016-01-26 23:30:18 +0100170#endif
Bram Moolenaare0874f82016-01-24 20:36:41 +0100171
Bram Moolenaard04a0202016-01-26 23:30:18 +0100172#ifdef FEAT_GUI_GTK
173 static void
174messageFromNetbeans(gpointer clientData,
175 gint unused1 UNUSED,
176 GdkInputCondition unused2 UNUSED)
Bram Moolenaare0874f82016-01-24 20:36:41 +0100177{
Bram Moolenaard04a0202016-01-26 23:30:18 +0100178 channel_read((int)(long)clientData);
Bram Moolenaare0874f82016-01-24 20:36:41 +0100179}
180#endif
181
182 static void
Bram Moolenaard04a0202016-01-26 23:30:18 +0100183channel_gui_register(int idx)
Bram Moolenaare0874f82016-01-24 20:36:41 +0100184{
Bram Moolenaard04a0202016-01-26 23:30:18 +0100185 channel_T *channel = &channels[idx];
186
187 if (!CH_HAS_GUI)
188 return;
189
190# ifdef FEAT_GUI_X11
191 /* tell notifier we are interested in being called
192 * when there is input on the editor connection socket
193 */
194 if (channel->ch_inputHandler == (XtInputId)NULL)
195 channel->ch_inputHandler =
196 XtAppAddInput((XtAppContext)app_context, channel->ch_fd,
197 (XtPointer)(XtInputReadMask + XtInputExceptMask),
Bram Moolenaar3b5f9292016-01-28 22:37:01 +0100198 messageFromNetbeans, (XtPointer)(long)idx);
Bram Moolenaard04a0202016-01-26 23:30:18 +0100199# else
200# ifdef FEAT_GUI_GTK
201 /*
202 * Tell gdk we are interested in being called when there
203 * is input on the editor connection socket
204 */
205 if (channel->ch_inputHandler == 0)
206 channel->ch_inputHandler =
207 gdk_input_add((gint)channel->ch_fd, (GdkInputCondition)
208 ((int)GDK_INPUT_READ + (int)GDK_INPUT_EXCEPTION),
209 messageFromNetbeans, (gpointer)(long)idx);
210# else
211# ifdef FEAT_GUI_W32
212 /*
213 * Tell Windows we are interested in receiving message when there
214 * is input on the editor connection socket.
Bram Moolenaard04a0202016-01-26 23:30:18 +0100215 */
216 if (channel->ch_inputHandler == -1)
217 channel->ch_inputHandler =
218 WSAAsyncSelect(channel->ch_fd, s_hwnd, WM_NETBEANS, FD_READ);
219# endif
220# endif
Bram Moolenaare0874f82016-01-24 20:36:41 +0100221# endif
Bram Moolenaard04a0202016-01-26 23:30:18 +0100222}
223
224/*
225 * Register any of our file descriptors with the GUI event handling system.
226 * Called when the GUI has started.
227 */
228 void
229channel_gui_register_all(void)
230{
231 int i;
232
233 for (i = 0; i < channel_count; ++i)
234 if (channels[i].ch_fd >= 0)
235 channel_gui_register(i);
236}
237
238 static void
239channel_gui_unregister(int idx)
240{
241 channel_T *channel = &channels[idx];
242
243# ifdef FEAT_GUI_X11
244 if (channel->ch_inputHandler != (XtInputId)NULL)
Bram Moolenaare0874f82016-01-24 20:36:41 +0100245 {
Bram Moolenaard04a0202016-01-26 23:30:18 +0100246 XtRemoveInput(channel->ch_inputHandler);
247 channel->ch_inputHandler = (XtInputId)NULL;
248 }
249# else
250# ifdef FEAT_GUI_GTK
251 if (channel->ch_inputHandler != 0)
252 {
253 gdk_input_remove(channel->ch_inputHandler);
254 channel->ch_inputHandler = 0;
255 }
256# else
257# ifdef FEAT_GUI_W32
258 if (channel->ch_inputHandler == 0)
259 {
Bram Moolenaar54e09e72016-01-26 23:49:31 +0100260 WSAAsyncSelect(channel->ch_fd, s_hwnd, 0, 0);
Bram Moolenaard04a0202016-01-26 23:30:18 +0100261 channel->ch_inputHandler = -1;
262 }
263# endif
264# endif
265# endif
266}
267
268#endif
269
270/*
271 * Open a channel to "hostname":"port".
272 * Returns the channel number for success.
273 * Returns a negative number for failure.
274 */
275 int
276channel_open(char *hostname, int port_in, void (*close_cb)(void))
277{
278 int sd;
279 struct sockaddr_in server;
280 struct hostent * host;
Bram Moolenaarf12d9832016-01-29 21:11:25 +0100281#ifdef WIN32
Bram Moolenaard04a0202016-01-26 23:30:18 +0100282 u_short port = port_in;
283#else
284 int port = port_in;
285#endif
286 int idx;
287
Bram Moolenaarf12d9832016-01-29 21:11:25 +0100288#ifdef WIN32
Bram Moolenaard04a0202016-01-26 23:30:18 +0100289 channel_init_winsock();
290#endif
291
292 idx = add_channel();
293 if (idx < 0)
294 {
295 CHERROR("All channels are in use\n", "");
296 EMSG(_("E999: All channels are in use"));
297 return -1;
298 }
299
300 if ((sd = (sock_T)socket(AF_INET, SOCK_STREAM, 0)) == (sock_T)-1)
301 {
302 CHERROR("error in socket() in channel_open()\n", "");
303 PERROR("E999: socket() in channel_open()");
304 return -1;
305 }
306
307 /* Get the server internet address and put into addr structure */
308 /* fill in the socket address structure and connect to server */
309 vim_memset((char *)&server, 0, sizeof(server));
310 server.sin_family = AF_INET;
311 server.sin_port = htons(port);
312 if ((host = gethostbyname(hostname)) == NULL)
313 {
314 CHERROR("error in gethostbyname() in channel_open()\n", "");
315 PERROR("E999: gethostbyname() in channel_open()");
316 sock_close(sd);
317 return -1;
318 }
319 memcpy((char *)&server.sin_addr, host->h_addr, host->h_length);
320
321 /* Connect to server */
322 if (connect(sd, (struct sockaddr *)&server, sizeof(server)))
323 {
324 SOCK_ERRNO;
325 CHERROR("channel_open: Connect failed with errno %d\n", errno);
326 if (errno == ECONNREFUSED)
327 {
328 sock_close(sd);
329 if ((sd = (sock_T)socket(AF_INET, SOCK_STREAM, 0)) == (sock_T)-1)
330 {
331 SOCK_ERRNO;
332 CHERROR("socket() retry in channel_open()\n", "");
333 PERROR("E999: socket() retry in channel_open()");
334 return -1;
335 }
336 if (connect(sd, (struct sockaddr *)&server, sizeof(server)))
337 {
338 int retries = 36;
339 int success = FALSE;
340
341 SOCK_ERRNO;
342 while (retries-- && ((errno == ECONNREFUSED)
343 || (errno == EINTR)))
344 {
345 CHERROR("retrying...\n", "");
346 mch_delay(3000L, TRUE);
347 ui_breakcheck();
348 if (got_int)
349 {
350 errno = EINTR;
351 break;
352 }
353 if (connect(sd, (struct sockaddr *)&server,
354 sizeof(server)) == 0)
355 {
356 success = TRUE;
357 break;
358 }
359 SOCK_ERRNO;
360 }
361 if (!success)
362 {
363 /* Get here when the server can't be found. */
364 CHERROR("Cannot connect to port after retry\n", "");
365 PERROR(_("E999: Cannot connect to port after retry2"));
366 sock_close(sd);
367 return -1;
368 }
369 }
370 }
371 else
372 {
373 CHERROR("Cannot connect to port\n", "");
374 PERROR(_("E999: Cannot connect to port"));
375 sock_close(sd);
376 return -1;
377 }
378 }
379
380 channels[idx].ch_fd = sd;
381 channels[idx].ch_close_cb = close_cb;
382
383#ifdef FEAT_GUI
384 channel_gui_register(idx);
385#endif
386
387 return idx;
388}
389
390/*
Bram Moolenaar3b5f9292016-01-28 22:37:01 +0100391 * Set the json mode of channel "idx" to TRUE or FALSE.
392 */
393 void
394channel_set_json_mode(int idx, int json_mode)
395{
396 channels[idx].ch_json_mode = json_mode;
397}
398
399/*
400 * Set the callback for channel "idx".
401 */
402 void
403channel_set_callback(int idx, char_u *callback)
404{
405 vim_free(channels[idx].ch_callback);
406 channels[idx].ch_callback = vim_strsave(callback);
407}
408
409/*
410 * Set the callback for channel "idx" for the next response.
411 */
412 void
413channel_set_req_callback(int idx, char_u *callback)
414{
415 vim_free(channels[idx].ch_req_callback);
416 channels[idx].ch_req_callback = callback == NULL
417 ? NULL : vim_strsave(callback);
418}
419
420/*
Bram Moolenaar20fb9f32016-01-30 23:20:33 +0100421 * Decode JSON "msg", which must have the form "[expr1, expr2]".
422 * Put "expr1" in "tv1".
423 * Put "expr2" in "tv2".
Bram Moolenaar3b5f9292016-01-28 22:37:01 +0100424 * Return OK or FAIL.
425 */
426 int
Bram Moolenaar20fb9f32016-01-30 23:20:33 +0100427channel_decode_json(char_u *msg, typval_T *tv1, typval_T *tv2)
Bram Moolenaar3b5f9292016-01-28 22:37:01 +0100428{
429 js_read_T reader;
430 typval_T listtv;
431
432 reader.js_buf = msg;
433 reader.js_eof = TRUE;
434 reader.js_used = 0;
435 json_decode(&reader, &listtv);
Bram Moolenaar20fb9f32016-01-30 23:20:33 +0100436
437 if (listtv.v_type == VAR_LIST && listtv.vval.v_list->lv_len == 2)
Bram Moolenaar3b5f9292016-01-28 22:37:01 +0100438 {
439 /* Move the item from the list and then change the type to avoid the
440 * item being freed. */
Bram Moolenaar20fb9f32016-01-30 23:20:33 +0100441 *tv1 = listtv.vval.v_list->lv_first->li_tv;
442 listtv.vval.v_list->lv_first->li_tv.v_type = VAR_NUMBER;
443 *tv2 = listtv.vval.v_list->lv_last->li_tv;
Bram Moolenaar3b5f9292016-01-28 22:37:01 +0100444 listtv.vval.v_list->lv_last->li_tv.v_type = VAR_NUMBER;
445 list_unref(listtv.vval.v_list);
446 return OK;
447 }
448
449 /* give error message? */
450 clear_tv(&listtv);
451 return FAIL;
452}
453
454/*
455 * Invoke the "callback" on channel "idx".
456 */
457 static void
Bram Moolenaar20fb9f32016-01-30 23:20:33 +0100458invoke_callback(int idx, char_u *callback, typval_T *argv)
Bram Moolenaar3b5f9292016-01-28 22:37:01 +0100459{
Bram Moolenaar3b5f9292016-01-28 22:37:01 +0100460 typval_T rettv;
461 int dummy;
Bram Moolenaar3b5f9292016-01-28 22:37:01 +0100462
463 argv[0].v_type = VAR_NUMBER;
464 argv[0].vval.v_number = idx;
465
Bram Moolenaar20fb9f32016-01-30 23:20:33 +0100466 call_func(callback, (int)STRLEN(callback),
467 &rettv, 2, argv, 0L, 0L, &dummy, TRUE, NULL);
468 /* If an echo command was used the cursor needs to be put back where
469 * it belongs. */
470 setcursor();
471 cursor_on();
472 out_flush();
473}
474
475 static void
476channel_exe_cmd(char_u *cmd, typval_T *arg)
477{
478 if (STRCMP(cmd, "ex") == 0)
479 {
480 if (arg->v_type == VAR_STRING)
481 do_cmdline_cmd(arg->vval.v_string);
482 else if (p_verbose > 2)
483 EMSG("E999: received ex command with non-string argument");
484 }
485 else if (STRCMP(cmd, "normal") == 0)
486 {
487 if (arg->v_type == VAR_STRING)
488 {
489 exarg_T ea;
490
491 ea.arg = arg->vval.v_string;
492 ea.addr_count = 0;
493 ea.forceit = TRUE; /* no mapping */
494 ex_normal(&ea);
495
496 update_screen(0);
497 showruler(FALSE);
498 setcursor();
499 out_flush();
500#ifdef FEAT_GUI
501 if (gui.in_use)
502 {
503 gui_update_cursor(FALSE, FALSE);
504 gui_mch_flush();
505 }
506#endif
507 }
508 else if (p_verbose > 2)
509 EMSG("E999: received normal command with non-string argument");
510 }
511 else if (p_verbose > 2)
512 EMSG2("E999: received unknown command: %s", cmd);
513}
514
515/*
516 * Invoke a callback for channel "idx" if needed.
517 */
518 static void
519may_invoke_callback(int idx)
520{
521 char_u *msg;
522 typval_T typetv;
523 typval_T argv[3];
524 char_u *cmd = NULL;
525 int seq_nr = -1;
526 int ret = OK;
527
528 if (channel_peek(idx) == NULL)
529 return;
530
Bram Moolenaar3b5f9292016-01-28 22:37:01 +0100531 /* Concatenate everything into one buffer.
532 * TODO: only read what the callback will use.
533 * TODO: avoid multiple allocations. */
534 while (channel_collapse(idx) == OK)
535 ;
536 msg = channel_get(idx);
537
538 if (channels[idx].ch_json_mode)
Bram Moolenaar20fb9f32016-01-30 23:20:33 +0100539 {
540 ret = channel_decode_json(msg, &typetv, &argv[1]);
541 if (ret == OK)
542 {
543 if (typetv.v_type == VAR_STRING)
544 cmd = typetv.vval.v_string;
545 else if (typetv.v_type == VAR_NUMBER)
546 seq_nr = typetv.vval.v_number;
547 }
548 }
Bram Moolenaar3b5f9292016-01-28 22:37:01 +0100549 else
550 {
551 argv[1].v_type = VAR_STRING;
552 argv[1].vval.v_string = msg;
553 }
554
555 if (ret == OK)
556 {
Bram Moolenaar20fb9f32016-01-30 23:20:33 +0100557 if (cmd != NULL)
558 {
559 channel_exe_cmd(cmd, &argv[1]);
560 }
561 else if (channels[idx].ch_req_callback != NULL && seq_nr != 0)
562 {
563 /* TODO: check the sequence number */
564 /* invoke the one-time callback */
565 invoke_callback(idx, channels[idx].ch_req_callback, argv);
566 channels[idx].ch_req_callback = NULL;
567 }
568 else if (channels[idx].ch_callback != NULL)
569 {
570 /* invoke the channel callback */
571 invoke_callback(idx, channels[idx].ch_callback, argv);
572 }
573 /* else: drop the message */
574
575 if (channels[idx].ch_json_mode)
576 {
577 clear_tv(&typetv);
578 clear_tv(&argv[1]);
579 }
Bram Moolenaar3b5f9292016-01-28 22:37:01 +0100580 }
Bram Moolenaar20fb9f32016-01-30 23:20:33 +0100581
Bram Moolenaar3b5f9292016-01-28 22:37:01 +0100582 vim_free(msg);
583}
584
585/*
Bram Moolenaard04a0202016-01-26 23:30:18 +0100586 * Return TRUE when channel "idx" is open.
Bram Moolenaar3b5f9292016-01-28 22:37:01 +0100587 * Also returns FALSE or invalid "idx".
Bram Moolenaard04a0202016-01-26 23:30:18 +0100588 */
589 int
590channel_is_open(int idx)
591{
Bram Moolenaar3b5f9292016-01-28 22:37:01 +0100592 return idx >= 0 && idx < channel_count && channels[idx].ch_fd >= 0;
Bram Moolenaard04a0202016-01-26 23:30:18 +0100593}
594
595/*
596 * Close channel "idx".
597 * This does not trigger the close callback.
598 */
599 void
600channel_close(int idx)
601{
602 channel_T *channel = &channels[idx];
603
604 if (channel->ch_fd >= 0)
605 {
606 sock_close(channel->ch_fd);
607 channel->ch_fd = -1;
608#ifdef FEAT_GUI
609 channel_gui_unregister(idx);
610#endif
Bram Moolenaar3b5f9292016-01-28 22:37:01 +0100611 vim_free(channel->ch_callback);
612 channel->ch_callback = NULL;
Bram Moolenaare0874f82016-01-24 20:36:41 +0100613 }
614}
615
Bram Moolenaard04a0202016-01-26 23:30:18 +0100616/*
617 * Store "buf[len]" on channel "idx".
Bram Moolenaar83162462016-01-28 23:10:07 +0100618 * Returns OK or FAIL.
Bram Moolenaard04a0202016-01-26 23:30:18 +0100619 */
Bram Moolenaar83162462016-01-28 23:10:07 +0100620 int
Bram Moolenaard04a0202016-01-26 23:30:18 +0100621channel_save(int idx, char_u *buf, int len)
622{
623 queue_T *node;
624 queue_T *head = &channels[idx].ch_head;
625
626 node = (queue_T *)alloc(sizeof(queue_T));
627 if (node == NULL)
Bram Moolenaar83162462016-01-28 23:10:07 +0100628 return FAIL; /* out of memory */
Bram Moolenaard04a0202016-01-26 23:30:18 +0100629 node->buffer = alloc(len + 1);
630 if (node->buffer == NULL)
631 {
632 vim_free(node);
Bram Moolenaar83162462016-01-28 23:10:07 +0100633 return FAIL; /* out of memory */
Bram Moolenaard04a0202016-01-26 23:30:18 +0100634 }
635 mch_memmove(node->buffer, buf, (size_t)len);
636 node->buffer[len] = NUL;
637
638 if (head->next == NULL) /* initialize circular queue */
639 {
640 head->next = head;
641 head->prev = head;
642 }
643
644 /* insert node at tail of queue */
645 node->next = head;
646 node->prev = head->prev;
647 head->prev->next = node;
648 head->prev = node;
649
650 if (debugfd != NULL)
651 {
652 fprintf(debugfd, "RECV on %d: ", idx);
Bram Moolenaar83162462016-01-28 23:10:07 +0100653 if (fwrite(buf, len, 1, debugfd) != 1)
654 return FAIL;
Bram Moolenaard04a0202016-01-26 23:30:18 +0100655 fprintf(debugfd, "\n");
656 }
Bram Moolenaar83162462016-01-28 23:10:07 +0100657 return OK;
Bram Moolenaard04a0202016-01-26 23:30:18 +0100658}
659
660/*
661 * Return the first buffer from the channel without removing it.
662 * Returns NULL if there is nothing.
663 */
664 char_u *
665channel_peek(int idx)
666{
667 queue_T *head = &channels[idx].ch_head;
668
669 if (head->next == head || head->next == NULL)
670 return NULL;
671 return head->next->buffer;
672}
673
674/*
675 * Return the first buffer from the channel and remove it.
676 * The caller must free it.
677 * Returns NULL if there is nothing.
678 */
679 char_u *
680channel_get(int idx)
681{
682 queue_T *head = &channels[idx].ch_head;
683 queue_T *node;
684 char_u *p;
685
686 if (head->next == head || head->next == NULL)
687 return NULL;
688 node = head->next;
689 /* dispose of the node but keep the buffer */
690 p = node->buffer;
691 head->next = node->next;
692 node->next->prev = node->prev;
693 vim_free(node);
694 return p;
695}
696
697/*
698 * Collapses the first and second buffer in the channel "idx".
699 * Returns FAIL if that is not possible.
700 */
701 int
702channel_collapse(int idx)
703{
704 queue_T *head = &channels[idx].ch_head;
705 queue_T *node = head->next;
706 char_u *p;
707
708 if (node == head || node == NULL || node->next == head)
709 return FAIL;
710
711 p = alloc((unsigned)(STRLEN(node->buffer)
712 + STRLEN(node->next->buffer) + 1));
713 if (p == NULL)
714 return FAIL; /* out of memory */
715 STRCPY(p, node->buffer);
716 STRCAT(p, node->next->buffer);
717 vim_free(node->next->buffer);
718 node->next->buffer = p;
719
720 /* dispose of the node and buffer */
721 head->next = node->next;
722 node->next->prev = node->prev;
723 vim_free(node->buffer);
724 vim_free(node);
725 return OK;
726}
727
728/*
729 * Clear the read buffer on channel "idx".
730 */
731 void
732channel_clear(int idx)
733{
734 queue_T *head = &channels[idx].ch_head;
735 queue_T *node = head->next;
736 queue_T *next;
737
738 while (node != NULL && node != head)
739 {
740 next = node->next;
741 vim_free(node->buffer);
742 vim_free(node);
743 if (next == head)
744 {
745 head->next = head;
746 head->prev = head;
747 break;
748 }
749 node = next;
750 }
751}
752
753/* Sent when the channel is found closed when reading. */
754#define DETACH_MSG "\"DETACH\"\n"
755
756/* Buffer size for reading incoming messages. */
757#define MAXMSGSIZE 4096
758
759/*
Bram Moolenaar3b5f9292016-01-28 22:37:01 +0100760 * Check for reading from "fd" with "timeout" msec.
761 * Return FAIL when there is nothing to read.
762 */
763 static int
764channel_wait(int fd, int timeout)
765{
766#ifdef HAVE_SELECT
767 struct timeval tval;
768 fd_set rfds;
769 int ret;
770
771 FD_ZERO(&rfds);
772 FD_SET(fd, &rfds);
773 tval.tv_sec = timeout / 1000;
774 tval.tv_usec = (timeout % 1000) * 1000;
775 for (;;)
776 {
777 ret = select(fd + 1, &rfds, NULL, NULL, &tval);
778# ifdef EINTR
779 if (ret == -1 && errno == EINTR)
780 continue;
781# endif
782 if (ret <= 0)
783 return FAIL;
784 break;
785 }
786#else
Bram Moolenaarb8b65112016-01-28 23:01:49 +0100787# ifdef HAVE_POLL
Bram Moolenaar3b5f9292016-01-28 22:37:01 +0100788 struct pollfd fds;
789
790 fds.fd = fd;
791 fds.events = POLLIN;
792 if (poll(&fds, 1, timeout) <= 0)
793 return FAIL;
Bram Moolenaarb8b65112016-01-28 23:01:49 +0100794# endif
Bram Moolenaar3b5f9292016-01-28 22:37:01 +0100795#endif
796 return OK;
797}
798
799/*
800 * Return a unique ID to be used in a message.
801 */
802 int
Bram Moolenaar7454a062016-01-30 15:14:10 +0100803channel_get_id(void)
Bram Moolenaar3b5f9292016-01-28 22:37:01 +0100804{
805 static int next_id = 1;
806
807 return next_id++;
808}
809
810/*
811 * Read from channel "idx" for as long as there is something to read.
812 * The data is put in the read queue.
Bram Moolenaard04a0202016-01-26 23:30:18 +0100813 */
814 void
815channel_read(int idx)
816{
817 static char_u *buf = NULL;
818 int len = 0;
819 int readlen = 0;
Bram Moolenaard04a0202016-01-26 23:30:18 +0100820 channel_T *channel = &channels[idx];
821
822 if (channel->ch_fd < 0)
823 {
824 CHLOG(idx, FALSE, "channel_read() called while socket is closed\n");
825 return;
826 }
827
828 /* Allocate a buffer to read into. */
829 if (buf == NULL)
830 {
831 buf = alloc(MAXMSGSIZE);
832 if (buf == NULL)
833 return; /* out of memory! */
834 }
835
836 /* Keep on reading for as long as there is something to read.
837 * Use select() or poll() to avoid blocking on a message that is exactly
838 * MAXMSGSIZE long. */
839 for (;;)
840 {
Bram Moolenaar3b5f9292016-01-28 22:37:01 +0100841 if (channel_wait(channel->ch_fd, 0) == FAIL)
Bram Moolenaard04a0202016-01-26 23:30:18 +0100842 break;
Bram Moolenaard04a0202016-01-26 23:30:18 +0100843 len = sock_read(channel->ch_fd, buf, MAXMSGSIZE);
844 if (len <= 0)
845 break; /* error or nothing more to read */
846
847 /* Store the read message in the queue. */
848 channel_save(idx, buf, len);
849 readlen += len;
850 if (len < MAXMSGSIZE)
851 break; /* did read everything that's available */
852 }
853
854 /* Reading a socket disconnection (readlen == 0), or a socket error. */
855 if (readlen <= 0)
856 {
857 /* Queue a "DETACH" netbeans message in the command queue in order to
858 * terminate the netbeans session later. Do not end the session here
859 * directly as we may be running in the context of a call to
860 * netbeans_parse_messages():
861 * netbeans_parse_messages
862 * -> autocmd triggered while processing the netbeans cmd
863 * -> ui_breakcheck
864 * -> gui event loop or select loop
865 * -> channel_read()
866 */
867 channel_save(idx, (char_u *)DETACH_MSG, (int)STRLEN(DETACH_MSG));
868
869 channel_close(idx);
870 if (channel->ch_close_cb != NULL)
871 (*channel->ch_close_cb)();
872
873 if (len < 0)
874 {
875 /* Todo: which channel? */
876 CHERROR("%s(): cannot from channel\n", "channel_read");
877 PERROR(_("E999: read from channel"));
878 }
879 }
880
881#if defined(CH_HAS_GUI) && defined(FEAT_GUI_GTK)
882 if (CH_HAS_GUI && gtk_main_level() > 0)
883 gtk_main_quit();
884#endif
885}
886
Bram Moolenaar3b5f9292016-01-28 22:37:01 +0100887/*
888 * Read from channel "idx". Blocks until there is something to read or the
889 * timeout expires.
890 * Returns what was read in allocated memory.
891 * Returns NULL in case of error or timeout.
892 */
893 char_u *
894channel_read_block(int idx)
895{
896 if (channel_peek(idx) == NULL)
897 {
898 /* Wait for up to 2 seconds.
899 * TODO: use timeout set on the channel. */
900 if (channel_wait(channels[idx].ch_fd, 2000) == FAIL)
Bram Moolenaar3b5f9292016-01-28 22:37:01 +0100901 return NULL;
Bram Moolenaar3b5f9292016-01-28 22:37:01 +0100902 channel_read(idx);
903 }
904
905 /* Concatenate everything into one buffer.
906 * TODO: avoid multiple allocations. */
907 while (channel_collapse(idx) == OK)
908 ;
909
Bram Moolenaar3b5f9292016-01-28 22:37:01 +0100910 return channel_get(idx);
911}
912
Bram Moolenaarf12d9832016-01-29 21:11:25 +0100913# if defined(WIN32) || defined(PROTO)
Bram Moolenaar85be35f2016-01-27 21:08:18 +0100914/*
915 * Lookup the channel index from the socket.
916 * Returns -1 when the socket isn't found.
917 */
918 int
919channel_socket2idx(sock_T fd)
920{
921 int i;
922
923 if (fd >= 0)
924 for (i = 0; i < channel_count; ++i)
925 if (channels[i].ch_fd == fd)
926 return i;
927 return -1;
928}
929# endif
930
Bram Moolenaard04a0202016-01-26 23:30:18 +0100931/*
932 * Write "buf" (NUL terminated string) to channel "idx".
933 * When "fun" is not NULL an error message might be given.
Bram Moolenaar3b5f9292016-01-28 22:37:01 +0100934 * Return FAIL or OK.
Bram Moolenaard04a0202016-01-26 23:30:18 +0100935 */
Bram Moolenaar3b5f9292016-01-28 22:37:01 +0100936 int
Bram Moolenaard04a0202016-01-26 23:30:18 +0100937channel_send(int idx, char_u *buf, char *fun)
938{
939 channel_T *channel = &channels[idx];
940 int len = (int)STRLEN(buf);
941
942 if (channel->ch_fd < 0)
943 {
944 if (!channel->ch_error && fun != NULL)
945 {
946 CHERROR(" %s(): write while not connected\n", fun);
947 EMSG2("E630: %s(): write while not connected", fun);
948 }
949 channel->ch_error = TRUE;
Bram Moolenaar3b5f9292016-01-28 22:37:01 +0100950 return FAIL;
Bram Moolenaard04a0202016-01-26 23:30:18 +0100951 }
Bram Moolenaar3b5f9292016-01-28 22:37:01 +0100952
953 if (sock_write(channel->ch_fd, buf, len) != len)
Bram Moolenaard04a0202016-01-26 23:30:18 +0100954 {
955 if (!channel->ch_error && fun != NULL)
956 {
957 CHERROR(" %s(): write failed\n", fun);
958 EMSG2("E631: %s(): write failed", fun);
959 }
960 channel->ch_error = TRUE;
Bram Moolenaar3b5f9292016-01-28 22:37:01 +0100961 return FAIL;
Bram Moolenaard04a0202016-01-26 23:30:18 +0100962 }
Bram Moolenaar3b5f9292016-01-28 22:37:01 +0100963
964 channel->ch_error = FALSE;
965 return OK;
Bram Moolenaard04a0202016-01-26 23:30:18 +0100966}
967
968# if (defined(UNIX) && !defined(HAVE_SELECT)) || defined(PROTO)
Bram Moolenaare0874f82016-01-24 20:36:41 +0100969/*
970 * Add open channels to the poll struct.
971 * Return the adjusted struct index.
972 * The type of "fds" is hidden to avoid problems with the function proto.
973 */
974 int
975channel_poll_setup(int nfd_in, void *fds_in)
976{
977 int nfd = nfd_in;
978 int i;
979 struct pollfd *fds = fds_in;
980
981 for (i = 0; i < channel_count; ++i)
982 if (channels[i].ch_fd >= 0)
983 {
984 channels[i].ch_idx = nfd;
985 fds[nfd].fd = channels[i].ch_fd;
986 fds[nfd].events = POLLIN;
987 nfd++;
988 }
989 else
990 channels[i].ch_idx = -1;
991
992 return nfd;
993}
994
995/*
996 * The type of "fds" is hidden to avoid problems with the function proto.
997 */
998 int
999channel_poll_check(int ret_in, void *fds_in)
1000{
1001 int ret = ret_in;
1002 int i;
1003 struct pollfd *fds = fds_in;
1004
1005 for (i = 0; i < channel_count; ++i)
1006 if (ret > 0 && channels[i].ch_idx != -1
1007 && fds[channels[i].ch_idx].revents & POLLIN)
1008 {
1009 channel_read(i);
1010 --ret;
1011 }
1012
1013 return ret;
1014}
Bram Moolenaard04a0202016-01-26 23:30:18 +01001015# endif /* UNIX && !HAVE_SELECT */
Bram Moolenaare0874f82016-01-24 20:36:41 +01001016
Bram Moolenaarf12d9832016-01-29 21:11:25 +01001017# if (!defined(FEAT_GUI_W32) && defined(HAVE_SELECT)) || defined(PROTO)
Bram Moolenaare0874f82016-01-24 20:36:41 +01001018/*
1019 * The type of "rfds" is hidden to avoid problems with the function proto.
1020 */
1021 int
1022channel_select_setup(int maxfd_in, void *rfds_in)
1023{
1024 int maxfd = maxfd_in;
1025 int i;
1026 fd_set *rfds = rfds_in;
1027
1028 for (i = 0; i < channel_count; ++i)
1029 if (channels[i].ch_fd >= 0)
1030 {
1031 FD_SET(channels[i].ch_fd, rfds);
1032 if (maxfd < channels[i].ch_fd)
1033 maxfd = channels[i].ch_fd;
1034 }
1035
1036 return maxfd;
1037}
1038
1039/*
1040 * The type of "rfds" is hidden to avoid problems with the function proto.
1041 */
1042 int
1043channel_select_check(int ret_in, void *rfds_in)
1044{
1045 int ret = ret_in;
1046 int i;
1047 fd_set *rfds = rfds_in;
1048
1049 for (i = 0; i < channel_count; ++i)
1050 if (ret > 0 && channels[i].ch_fd >= 0
1051 && FD_ISSET(channels[i].ch_fd, rfds))
1052 {
1053 channel_read(i);
1054 --ret;
1055 }
1056
1057 return ret;
1058}
Bram Moolenaarf12d9832016-01-29 21:11:25 +01001059# endif /* !FEAT_GUI_W32 && HAVE_SELECT */
Bram Moolenaare0874f82016-01-24 20:36:41 +01001060
Bram Moolenaar20fb9f32016-01-30 23:20:33 +01001061/*
1062 * Invoked from the main loop when it's save to execute received commands.
1063 */
1064 void
1065channel_parse_messages(void)
1066{
1067 int i;
1068
1069 for (i = 0; i < channel_count; ++i)
1070 may_invoke_callback(i);
1071}
1072
Bram Moolenaare0874f82016-01-24 20:36:41 +01001073#endif /* FEAT_CHANNEL */