blob: 2a75342f2dd539a2f0459cbb42c548672c3ca438 [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 */
102 int ch_will_block; /* do not use callback right now */
103
104 int ch_json_mode;
Bram Moolenaare0874f82016-01-24 20:36:41 +0100105} channel_T;
106
Bram Moolenaard04a0202016-01-26 23:30:18 +0100107/*
108 * Information about all channels.
109 * There can be gaps for closed channels, they will be reused later.
110 */
Bram Moolenaare0874f82016-01-24 20:36:41 +0100111static channel_T *channels = NULL;
112static int channel_count = 0;
113
114/*
Bram Moolenaard04a0202016-01-26 23:30:18 +0100115 * TODO: open debug file when desired.
116 */
117FILE *debugfd = NULL;
118
119/*
Bram Moolenaare0874f82016-01-24 20:36:41 +0100120 * Add a new channel slot, return the index.
Bram Moolenaard04a0202016-01-26 23:30:18 +0100121 * The channel isn't actually used into ch_fd is set >= 0;
122 * Returns -1 if all channels are in use.
Bram Moolenaare0874f82016-01-24 20:36:41 +0100123 */
124 static int
125add_channel(void)
126{
127 int idx;
128 channel_T *new_channels;
129
130 if (channels != NULL)
131 for (idx = 0; idx < channel_count; ++idx)
132 if (channels[idx].ch_fd < 0)
133 /* re-use a closed channel slot */
134 return idx;
135 if (channel_count == MAX_OPEN_CHANNELS)
136 return -1;
Bram Moolenaard04a0202016-01-26 23:30:18 +0100137 new_channels = (channel_T *)alloc(sizeof(channel_T) * (channel_count + 1));
Bram Moolenaare0874f82016-01-24 20:36:41 +0100138 if (new_channels == NULL)
139 return -1;
140 if (channels != NULL)
141 mch_memmove(new_channels, channels, sizeof(channel_T) * channel_count);
142 channels = new_channels;
Bram Moolenaard04a0202016-01-26 23:30:18 +0100143 (void)vim_memset(&channels[channel_count], 0, sizeof(channel_T));
144
Bram Moolenaare0874f82016-01-24 20:36:41 +0100145 channels[channel_count].ch_fd = (sock_T)-1;
Bram Moolenaard04a0202016-01-26 23:30:18 +0100146#ifdef FEAT_GUI_X11
147 channels[channel_count].ch_inputHandler = (XtInputId)NULL;
148#endif
149#ifdef FEAT_GUI_GTK
150 channels[channel_count].ch_inputHandler = 0;
151#endif
152#ifdef FEAT_GUI_W32
153 channels[channel_count].ch_inputHandler = -1;
154#endif
Bram Moolenaare0874f82016-01-24 20:36:41 +0100155
156 return channel_count++;
157}
158
Bram Moolenaard04a0202016-01-26 23:30:18 +0100159#if defined(FEAT_GUI) || defined(PROTO)
Bram Moolenaare0874f82016-01-24 20:36:41 +0100160/*
Bram Moolenaard04a0202016-01-26 23:30:18 +0100161 * Read a command from netbeans.
Bram Moolenaare0874f82016-01-24 20:36:41 +0100162 */
Bram Moolenaard04a0202016-01-26 23:30:18 +0100163#ifdef FEAT_GUI_X11
164 static void
165messageFromNetbeans(XtPointer clientData,
166 int *unused1 UNUSED,
167 XtInputId *unused2 UNUSED)
Bram Moolenaare0874f82016-01-24 20:36:41 +0100168{
Bram Moolenaard04a0202016-01-26 23:30:18 +0100169 channel_read((int)(long)clientData);
Bram Moolenaare0874f82016-01-24 20:36:41 +0100170}
Bram Moolenaard04a0202016-01-26 23:30:18 +0100171#endif
Bram Moolenaare0874f82016-01-24 20:36:41 +0100172
Bram Moolenaard04a0202016-01-26 23:30:18 +0100173#ifdef FEAT_GUI_GTK
174 static void
175messageFromNetbeans(gpointer clientData,
176 gint unused1 UNUSED,
177 GdkInputCondition unused2 UNUSED)
Bram Moolenaare0874f82016-01-24 20:36:41 +0100178{
Bram Moolenaard04a0202016-01-26 23:30:18 +0100179 channel_read((int)(long)clientData);
Bram Moolenaare0874f82016-01-24 20:36:41 +0100180}
181#endif
182
183 static void
Bram Moolenaard04a0202016-01-26 23:30:18 +0100184channel_gui_register(int idx)
Bram Moolenaare0874f82016-01-24 20:36:41 +0100185{
Bram Moolenaard04a0202016-01-26 23:30:18 +0100186 channel_T *channel = &channels[idx];
187
188 if (!CH_HAS_GUI)
189 return;
190
191# ifdef FEAT_GUI_X11
192 /* tell notifier we are interested in being called
193 * when there is input on the editor connection socket
194 */
195 if (channel->ch_inputHandler == (XtInputId)NULL)
196 channel->ch_inputHandler =
197 XtAppAddInput((XtAppContext)app_context, channel->ch_fd,
198 (XtPointer)(XtInputReadMask + XtInputExceptMask),
Bram Moolenaar3b5f9292016-01-28 22:37:01 +0100199 messageFromNetbeans, (XtPointer)(long)idx);
Bram Moolenaard04a0202016-01-26 23:30:18 +0100200# else
201# ifdef FEAT_GUI_GTK
202 /*
203 * Tell gdk we are interested in being called when there
204 * is input on the editor connection socket
205 */
206 if (channel->ch_inputHandler == 0)
207 channel->ch_inputHandler =
208 gdk_input_add((gint)channel->ch_fd, (GdkInputCondition)
209 ((int)GDK_INPUT_READ + (int)GDK_INPUT_EXCEPTION),
210 messageFromNetbeans, (gpointer)(long)idx);
211# else
212# ifdef FEAT_GUI_W32
213 /*
214 * Tell Windows we are interested in receiving message when there
215 * is input on the editor connection socket.
Bram Moolenaard04a0202016-01-26 23:30:18 +0100216 */
217 if (channel->ch_inputHandler == -1)
218 channel->ch_inputHandler =
219 WSAAsyncSelect(channel->ch_fd, s_hwnd, WM_NETBEANS, FD_READ);
220# endif
221# endif
Bram Moolenaare0874f82016-01-24 20:36:41 +0100222# endif
Bram Moolenaard04a0202016-01-26 23:30:18 +0100223}
224
225/*
226 * Register any of our file descriptors with the GUI event handling system.
227 * Called when the GUI has started.
228 */
229 void
230channel_gui_register_all(void)
231{
232 int i;
233
234 for (i = 0; i < channel_count; ++i)
235 if (channels[i].ch_fd >= 0)
236 channel_gui_register(i);
237}
238
239 static void
240channel_gui_unregister(int idx)
241{
242 channel_T *channel = &channels[idx];
243
244# ifdef FEAT_GUI_X11
245 if (channel->ch_inputHandler != (XtInputId)NULL)
Bram Moolenaare0874f82016-01-24 20:36:41 +0100246 {
Bram Moolenaard04a0202016-01-26 23:30:18 +0100247 XtRemoveInput(channel->ch_inputHandler);
248 channel->ch_inputHandler = (XtInputId)NULL;
249 }
250# else
251# ifdef FEAT_GUI_GTK
252 if (channel->ch_inputHandler != 0)
253 {
254 gdk_input_remove(channel->ch_inputHandler);
255 channel->ch_inputHandler = 0;
256 }
257# else
258# ifdef FEAT_GUI_W32
259 if (channel->ch_inputHandler == 0)
260 {
Bram Moolenaar54e09e72016-01-26 23:49:31 +0100261 WSAAsyncSelect(channel->ch_fd, s_hwnd, 0, 0);
Bram Moolenaard04a0202016-01-26 23:30:18 +0100262 channel->ch_inputHandler = -1;
263 }
264# endif
265# endif
266# endif
267}
268
269#endif
270
271/*
272 * Open a channel to "hostname":"port".
273 * Returns the channel number for success.
274 * Returns a negative number for failure.
275 */
276 int
277channel_open(char *hostname, int port_in, void (*close_cb)(void))
278{
279 int sd;
280 struct sockaddr_in server;
281 struct hostent * host;
Bram Moolenaarf12d9832016-01-29 21:11:25 +0100282#ifdef WIN32
Bram Moolenaard04a0202016-01-26 23:30:18 +0100283 u_short port = port_in;
284#else
285 int port = port_in;
286#endif
287 int idx;
288
Bram Moolenaarf12d9832016-01-29 21:11:25 +0100289#ifdef WIN32
Bram Moolenaard04a0202016-01-26 23:30:18 +0100290 channel_init_winsock();
291#endif
292
293 idx = add_channel();
294 if (idx < 0)
295 {
296 CHERROR("All channels are in use\n", "");
297 EMSG(_("E999: All channels are in use"));
298 return -1;
299 }
300
301 if ((sd = (sock_T)socket(AF_INET, SOCK_STREAM, 0)) == (sock_T)-1)
302 {
303 CHERROR("error in socket() in channel_open()\n", "");
304 PERROR("E999: socket() in channel_open()");
305 return -1;
306 }
307
308 /* Get the server internet address and put into addr structure */
309 /* fill in the socket address structure and connect to server */
310 vim_memset((char *)&server, 0, sizeof(server));
311 server.sin_family = AF_INET;
312 server.sin_port = htons(port);
313 if ((host = gethostbyname(hostname)) == NULL)
314 {
315 CHERROR("error in gethostbyname() in channel_open()\n", "");
316 PERROR("E999: gethostbyname() in channel_open()");
317 sock_close(sd);
318 return -1;
319 }
320 memcpy((char *)&server.sin_addr, host->h_addr, host->h_length);
321
322 /* Connect to server */
323 if (connect(sd, (struct sockaddr *)&server, sizeof(server)))
324 {
325 SOCK_ERRNO;
326 CHERROR("channel_open: Connect failed with errno %d\n", errno);
327 if (errno == ECONNREFUSED)
328 {
329 sock_close(sd);
330 if ((sd = (sock_T)socket(AF_INET, SOCK_STREAM, 0)) == (sock_T)-1)
331 {
332 SOCK_ERRNO;
333 CHERROR("socket() retry in channel_open()\n", "");
334 PERROR("E999: socket() retry in channel_open()");
335 return -1;
336 }
337 if (connect(sd, (struct sockaddr *)&server, sizeof(server)))
338 {
339 int retries = 36;
340 int success = FALSE;
341
342 SOCK_ERRNO;
343 while (retries-- && ((errno == ECONNREFUSED)
344 || (errno == EINTR)))
345 {
346 CHERROR("retrying...\n", "");
347 mch_delay(3000L, TRUE);
348 ui_breakcheck();
349 if (got_int)
350 {
351 errno = EINTR;
352 break;
353 }
354 if (connect(sd, (struct sockaddr *)&server,
355 sizeof(server)) == 0)
356 {
357 success = TRUE;
358 break;
359 }
360 SOCK_ERRNO;
361 }
362 if (!success)
363 {
364 /* Get here when the server can't be found. */
365 CHERROR("Cannot connect to port after retry\n", "");
366 PERROR(_("E999: Cannot connect to port after retry2"));
367 sock_close(sd);
368 return -1;
369 }
370 }
371 }
372 else
373 {
374 CHERROR("Cannot connect to port\n", "");
375 PERROR(_("E999: Cannot connect to port"));
376 sock_close(sd);
377 return -1;
378 }
379 }
380
381 channels[idx].ch_fd = sd;
382 channels[idx].ch_close_cb = close_cb;
383
384#ifdef FEAT_GUI
385 channel_gui_register(idx);
386#endif
387
388 return idx;
389}
390
391/*
Bram Moolenaar3b5f9292016-01-28 22:37:01 +0100392 * Set the json mode of channel "idx" to TRUE or FALSE.
393 */
394 void
395channel_set_json_mode(int idx, int json_mode)
396{
397 channels[idx].ch_json_mode = json_mode;
398}
399
400/*
401 * Set the callback for channel "idx".
402 */
403 void
404channel_set_callback(int idx, char_u *callback)
405{
406 vim_free(channels[idx].ch_callback);
407 channels[idx].ch_callback = vim_strsave(callback);
408}
409
410/*
411 * Set the callback for channel "idx" for the next response.
412 */
413 void
414channel_set_req_callback(int idx, char_u *callback)
415{
416 vim_free(channels[idx].ch_req_callback);
417 channels[idx].ch_req_callback = callback == NULL
418 ? NULL : vim_strsave(callback);
419}
420
421/*
422 * Set the flag that the callback for channel "idx" should not be used now.
423 */
424 void
425channel_will_block(int idx)
426{
427 channels[idx].ch_will_block = TRUE;
428}
429
430/*
431 * Decode JSON "msg", which must have the form "[nr, expr]".
432 * Put "expr" in "tv".
433 * Return OK or FAIL.
434 */
435 int
436channel_decode_json(char_u *msg, typval_T *tv)
437{
438 js_read_T reader;
439 typval_T listtv;
440
441 reader.js_buf = msg;
442 reader.js_eof = TRUE;
443 reader.js_used = 0;
444 json_decode(&reader, &listtv);
445 /* TODO: use the sequence number */
446 if (listtv.v_type == VAR_LIST
447 && listtv.vval.v_list->lv_len == 2
448 && listtv.vval.v_list->lv_first->li_tv.v_type == VAR_NUMBER)
449 {
450 /* Move the item from the list and then change the type to avoid the
451 * item being freed. */
452 *tv = listtv.vval.v_list->lv_last->li_tv;
453 listtv.vval.v_list->lv_last->li_tv.v_type = VAR_NUMBER;
454 list_unref(listtv.vval.v_list);
455 return OK;
456 }
457
458 /* give error message? */
459 clear_tv(&listtv);
460 return FAIL;
461}
462
463/*
464 * Invoke the "callback" on channel "idx".
465 */
466 static void
467invoke_callback(int idx, char_u *callback)
468{
469 typval_T argv[3];
470 typval_T rettv;
471 int dummy;
472 char_u *msg;
473 int ret = OK;
474
475 argv[0].v_type = VAR_NUMBER;
476 argv[0].vval.v_number = idx;
477
478 /* Concatenate everything into one buffer.
479 * TODO: only read what the callback will use.
480 * TODO: avoid multiple allocations. */
481 while (channel_collapse(idx) == OK)
482 ;
483 msg = channel_get(idx);
484
485 if (channels[idx].ch_json_mode)
486 ret = channel_decode_json(msg, &argv[1]);
487 else
488 {
489 argv[1].v_type = VAR_STRING;
490 argv[1].vval.v_string = msg;
491 }
492
493 if (ret == OK)
494 {
495 call_func(callback, (int)STRLEN(callback),
496 &rettv, 2, argv, 0L, 0L, &dummy, TRUE, NULL);
497 /* If an echo command was used the cursor needs to be put back where
498 * it belongs. */
499 setcursor();
500 cursor_on();
501 out_flush();
502 }
503 vim_free(msg);
504}
505
506/*
507 * Invoke a callback for channel "idx" if needed.
508 */
509 static void
510may_invoke_callback(int idx)
511{
512 if (channels[idx].ch_will_block)
513 return;
514 if (channel_peek(idx) == NULL)
515 return;
516
517 if (channels[idx].ch_req_callback != NULL)
518 {
519 /* invoke the one-time callback */
520 invoke_callback(idx, channels[idx].ch_req_callback);
521 channels[idx].ch_req_callback = NULL;
522 return;
523 }
524
525 if (channels[idx].ch_callback != NULL)
526 /* invoke the channel callback */
527 invoke_callback(idx, channels[idx].ch_callback);
528}
529
530/*
Bram Moolenaard04a0202016-01-26 23:30:18 +0100531 * Return TRUE when channel "idx" is open.
Bram Moolenaar3b5f9292016-01-28 22:37:01 +0100532 * Also returns FALSE or invalid "idx".
Bram Moolenaard04a0202016-01-26 23:30:18 +0100533 */
534 int
535channel_is_open(int idx)
536{
Bram Moolenaar3b5f9292016-01-28 22:37:01 +0100537 return idx >= 0 && idx < channel_count && channels[idx].ch_fd >= 0;
Bram Moolenaard04a0202016-01-26 23:30:18 +0100538}
539
540/*
541 * Close channel "idx".
542 * This does not trigger the close callback.
543 */
544 void
545channel_close(int idx)
546{
547 channel_T *channel = &channels[idx];
548
549 if (channel->ch_fd >= 0)
550 {
551 sock_close(channel->ch_fd);
552 channel->ch_fd = -1;
553#ifdef FEAT_GUI
554 channel_gui_unregister(idx);
555#endif
Bram Moolenaar3b5f9292016-01-28 22:37:01 +0100556 vim_free(channel->ch_callback);
557 channel->ch_callback = NULL;
Bram Moolenaare0874f82016-01-24 20:36:41 +0100558 }
559}
560
Bram Moolenaard04a0202016-01-26 23:30:18 +0100561/*
562 * Store "buf[len]" on channel "idx".
Bram Moolenaar83162462016-01-28 23:10:07 +0100563 * Returns OK or FAIL.
Bram Moolenaard04a0202016-01-26 23:30:18 +0100564 */
Bram Moolenaar83162462016-01-28 23:10:07 +0100565 int
Bram Moolenaard04a0202016-01-26 23:30:18 +0100566channel_save(int idx, char_u *buf, int len)
567{
568 queue_T *node;
569 queue_T *head = &channels[idx].ch_head;
570
571 node = (queue_T *)alloc(sizeof(queue_T));
572 if (node == NULL)
Bram Moolenaar83162462016-01-28 23:10:07 +0100573 return FAIL; /* out of memory */
Bram Moolenaard04a0202016-01-26 23:30:18 +0100574 node->buffer = alloc(len + 1);
575 if (node->buffer == NULL)
576 {
577 vim_free(node);
Bram Moolenaar83162462016-01-28 23:10:07 +0100578 return FAIL; /* out of memory */
Bram Moolenaard04a0202016-01-26 23:30:18 +0100579 }
580 mch_memmove(node->buffer, buf, (size_t)len);
581 node->buffer[len] = NUL;
582
583 if (head->next == NULL) /* initialize circular queue */
584 {
585 head->next = head;
586 head->prev = head;
587 }
588
589 /* insert node at tail of queue */
590 node->next = head;
591 node->prev = head->prev;
592 head->prev->next = node;
593 head->prev = node;
594
595 if (debugfd != NULL)
596 {
597 fprintf(debugfd, "RECV on %d: ", idx);
Bram Moolenaar83162462016-01-28 23:10:07 +0100598 if (fwrite(buf, len, 1, debugfd) != 1)
599 return FAIL;
Bram Moolenaard04a0202016-01-26 23:30:18 +0100600 fprintf(debugfd, "\n");
601 }
Bram Moolenaar83162462016-01-28 23:10:07 +0100602 return OK;
Bram Moolenaard04a0202016-01-26 23:30:18 +0100603}
604
605/*
606 * Return the first buffer from the channel without removing it.
607 * Returns NULL if there is nothing.
608 */
609 char_u *
610channel_peek(int idx)
611{
612 queue_T *head = &channels[idx].ch_head;
613
614 if (head->next == head || head->next == NULL)
615 return NULL;
616 return head->next->buffer;
617}
618
619/*
620 * Return the first buffer from the channel and remove it.
621 * The caller must free it.
622 * Returns NULL if there is nothing.
623 */
624 char_u *
625channel_get(int idx)
626{
627 queue_T *head = &channels[idx].ch_head;
628 queue_T *node;
629 char_u *p;
630
631 if (head->next == head || head->next == NULL)
632 return NULL;
633 node = head->next;
634 /* dispose of the node but keep the buffer */
635 p = node->buffer;
636 head->next = node->next;
637 node->next->prev = node->prev;
638 vim_free(node);
639 return p;
640}
641
642/*
643 * Collapses the first and second buffer in the channel "idx".
644 * Returns FAIL if that is not possible.
645 */
646 int
647channel_collapse(int idx)
648{
649 queue_T *head = &channels[idx].ch_head;
650 queue_T *node = head->next;
651 char_u *p;
652
653 if (node == head || node == NULL || node->next == head)
654 return FAIL;
655
656 p = alloc((unsigned)(STRLEN(node->buffer)
657 + STRLEN(node->next->buffer) + 1));
658 if (p == NULL)
659 return FAIL; /* out of memory */
660 STRCPY(p, node->buffer);
661 STRCAT(p, node->next->buffer);
662 vim_free(node->next->buffer);
663 node->next->buffer = p;
664
665 /* dispose of the node and buffer */
666 head->next = node->next;
667 node->next->prev = node->prev;
668 vim_free(node->buffer);
669 vim_free(node);
670 return OK;
671}
672
673/*
674 * Clear the read buffer on channel "idx".
675 */
676 void
677channel_clear(int idx)
678{
679 queue_T *head = &channels[idx].ch_head;
680 queue_T *node = head->next;
681 queue_T *next;
682
683 while (node != NULL && node != head)
684 {
685 next = node->next;
686 vim_free(node->buffer);
687 vim_free(node);
688 if (next == head)
689 {
690 head->next = head;
691 head->prev = head;
692 break;
693 }
694 node = next;
695 }
696}
697
698/* Sent when the channel is found closed when reading. */
699#define DETACH_MSG "\"DETACH\"\n"
700
701/* Buffer size for reading incoming messages. */
702#define MAXMSGSIZE 4096
703
704/*
Bram Moolenaar3b5f9292016-01-28 22:37:01 +0100705 * Check for reading from "fd" with "timeout" msec.
706 * Return FAIL when there is nothing to read.
707 */
708 static int
709channel_wait(int fd, int timeout)
710{
711#ifdef HAVE_SELECT
712 struct timeval tval;
713 fd_set rfds;
714 int ret;
715
716 FD_ZERO(&rfds);
717 FD_SET(fd, &rfds);
718 tval.tv_sec = timeout / 1000;
719 tval.tv_usec = (timeout % 1000) * 1000;
720 for (;;)
721 {
722 ret = select(fd + 1, &rfds, NULL, NULL, &tval);
723# ifdef EINTR
724 if (ret == -1 && errno == EINTR)
725 continue;
726# endif
727 if (ret <= 0)
728 return FAIL;
729 break;
730 }
731#else
Bram Moolenaarb8b65112016-01-28 23:01:49 +0100732# ifdef HAVE_POLL
Bram Moolenaar3b5f9292016-01-28 22:37:01 +0100733 struct pollfd fds;
734
735 fds.fd = fd;
736 fds.events = POLLIN;
737 if (poll(&fds, 1, timeout) <= 0)
738 return FAIL;
Bram Moolenaarb8b65112016-01-28 23:01:49 +0100739# endif
Bram Moolenaar3b5f9292016-01-28 22:37:01 +0100740#endif
741 return OK;
742}
743
744/*
745 * Return a unique ID to be used in a message.
746 */
747 int
Bram Moolenaar7454a062016-01-30 15:14:10 +0100748channel_get_id(void)
Bram Moolenaar3b5f9292016-01-28 22:37:01 +0100749{
750 static int next_id = 1;
751
752 return next_id++;
753}
754
755/*
756 * Read from channel "idx" for as long as there is something to read.
757 * The data is put in the read queue.
Bram Moolenaard04a0202016-01-26 23:30:18 +0100758 */
759 void
760channel_read(int idx)
761{
762 static char_u *buf = NULL;
763 int len = 0;
764 int readlen = 0;
Bram Moolenaard04a0202016-01-26 23:30:18 +0100765 channel_T *channel = &channels[idx];
766
767 if (channel->ch_fd < 0)
768 {
769 CHLOG(idx, FALSE, "channel_read() called while socket is closed\n");
770 return;
771 }
772
773 /* Allocate a buffer to read into. */
774 if (buf == NULL)
775 {
776 buf = alloc(MAXMSGSIZE);
777 if (buf == NULL)
778 return; /* out of memory! */
779 }
780
781 /* Keep on reading for as long as there is something to read.
782 * Use select() or poll() to avoid blocking on a message that is exactly
783 * MAXMSGSIZE long. */
784 for (;;)
785 {
Bram Moolenaar3b5f9292016-01-28 22:37:01 +0100786 if (channel_wait(channel->ch_fd, 0) == FAIL)
Bram Moolenaard04a0202016-01-26 23:30:18 +0100787 break;
Bram Moolenaard04a0202016-01-26 23:30:18 +0100788 len = sock_read(channel->ch_fd, buf, MAXMSGSIZE);
789 if (len <= 0)
790 break; /* error or nothing more to read */
791
792 /* Store the read message in the queue. */
793 channel_save(idx, buf, len);
794 readlen += len;
795 if (len < MAXMSGSIZE)
796 break; /* did read everything that's available */
797 }
798
799 /* Reading a socket disconnection (readlen == 0), or a socket error. */
800 if (readlen <= 0)
801 {
802 /* Queue a "DETACH" netbeans message in the command queue in order to
803 * terminate the netbeans session later. Do not end the session here
804 * directly as we may be running in the context of a call to
805 * netbeans_parse_messages():
806 * netbeans_parse_messages
807 * -> autocmd triggered while processing the netbeans cmd
808 * -> ui_breakcheck
809 * -> gui event loop or select loop
810 * -> channel_read()
811 */
812 channel_save(idx, (char_u *)DETACH_MSG, (int)STRLEN(DETACH_MSG));
813
814 channel_close(idx);
815 if (channel->ch_close_cb != NULL)
816 (*channel->ch_close_cb)();
817
818 if (len < 0)
819 {
820 /* Todo: which channel? */
821 CHERROR("%s(): cannot from channel\n", "channel_read");
822 PERROR(_("E999: read from channel"));
823 }
824 }
825
Bram Moolenaar3b5f9292016-01-28 22:37:01 +0100826 may_invoke_callback(idx);
827
Bram Moolenaard04a0202016-01-26 23:30:18 +0100828#if defined(CH_HAS_GUI) && defined(FEAT_GUI_GTK)
829 if (CH_HAS_GUI && gtk_main_level() > 0)
830 gtk_main_quit();
831#endif
832}
833
Bram Moolenaar3b5f9292016-01-28 22:37:01 +0100834/*
835 * Read from channel "idx". Blocks until there is something to read or the
836 * timeout expires.
837 * Returns what was read in allocated memory.
838 * Returns NULL in case of error or timeout.
839 */
840 char_u *
841channel_read_block(int idx)
842{
843 if (channel_peek(idx) == NULL)
844 {
845 /* Wait for up to 2 seconds.
846 * TODO: use timeout set on the channel. */
847 if (channel_wait(channels[idx].ch_fd, 2000) == FAIL)
848 {
849 channels[idx].ch_will_block = FALSE;
850 return NULL;
851 }
852 channel_read(idx);
853 }
854
855 /* Concatenate everything into one buffer.
856 * TODO: avoid multiple allocations. */
857 while (channel_collapse(idx) == OK)
858 ;
859
860 channels[idx].ch_will_block = FALSE;
861 return channel_get(idx);
862}
863
Bram Moolenaarf12d9832016-01-29 21:11:25 +0100864# if defined(WIN32) || defined(PROTO)
Bram Moolenaar85be35f2016-01-27 21:08:18 +0100865/*
866 * Lookup the channel index from the socket.
867 * Returns -1 when the socket isn't found.
868 */
869 int
870channel_socket2idx(sock_T fd)
871{
872 int i;
873
874 if (fd >= 0)
875 for (i = 0; i < channel_count; ++i)
876 if (channels[i].ch_fd == fd)
877 return i;
878 return -1;
879}
880# endif
881
Bram Moolenaard04a0202016-01-26 23:30:18 +0100882/*
883 * Write "buf" (NUL terminated string) to channel "idx".
884 * When "fun" is not NULL an error message might be given.
Bram Moolenaar3b5f9292016-01-28 22:37:01 +0100885 * Return FAIL or OK.
Bram Moolenaard04a0202016-01-26 23:30:18 +0100886 */
Bram Moolenaar3b5f9292016-01-28 22:37:01 +0100887 int
Bram Moolenaard04a0202016-01-26 23:30:18 +0100888channel_send(int idx, char_u *buf, char *fun)
889{
890 channel_T *channel = &channels[idx];
891 int len = (int)STRLEN(buf);
892
893 if (channel->ch_fd < 0)
894 {
895 if (!channel->ch_error && fun != NULL)
896 {
897 CHERROR(" %s(): write while not connected\n", fun);
898 EMSG2("E630: %s(): write while not connected", fun);
899 }
900 channel->ch_error = TRUE;
Bram Moolenaar3b5f9292016-01-28 22:37:01 +0100901 return FAIL;
Bram Moolenaard04a0202016-01-26 23:30:18 +0100902 }
Bram Moolenaar3b5f9292016-01-28 22:37:01 +0100903
904 if (sock_write(channel->ch_fd, buf, len) != len)
Bram Moolenaard04a0202016-01-26 23:30:18 +0100905 {
906 if (!channel->ch_error && fun != NULL)
907 {
908 CHERROR(" %s(): write failed\n", fun);
909 EMSG2("E631: %s(): write failed", fun);
910 }
911 channel->ch_error = TRUE;
Bram Moolenaar3b5f9292016-01-28 22:37:01 +0100912 return FAIL;
Bram Moolenaard04a0202016-01-26 23:30:18 +0100913 }
Bram Moolenaar3b5f9292016-01-28 22:37:01 +0100914
915 channel->ch_error = FALSE;
916 return OK;
Bram Moolenaard04a0202016-01-26 23:30:18 +0100917}
918
919# if (defined(UNIX) && !defined(HAVE_SELECT)) || defined(PROTO)
Bram Moolenaare0874f82016-01-24 20:36:41 +0100920/*
921 * Add open channels to the poll struct.
922 * Return the adjusted struct index.
923 * The type of "fds" is hidden to avoid problems with the function proto.
924 */
925 int
926channel_poll_setup(int nfd_in, void *fds_in)
927{
928 int nfd = nfd_in;
929 int i;
930 struct pollfd *fds = fds_in;
931
932 for (i = 0; i < channel_count; ++i)
933 if (channels[i].ch_fd >= 0)
934 {
935 channels[i].ch_idx = nfd;
936 fds[nfd].fd = channels[i].ch_fd;
937 fds[nfd].events = POLLIN;
938 nfd++;
939 }
940 else
941 channels[i].ch_idx = -1;
942
943 return nfd;
944}
945
946/*
947 * The type of "fds" is hidden to avoid problems with the function proto.
948 */
949 int
950channel_poll_check(int ret_in, void *fds_in)
951{
952 int ret = ret_in;
953 int i;
954 struct pollfd *fds = fds_in;
955
956 for (i = 0; i < channel_count; ++i)
957 if (ret > 0 && channels[i].ch_idx != -1
958 && fds[channels[i].ch_idx].revents & POLLIN)
959 {
960 channel_read(i);
961 --ret;
962 }
963
964 return ret;
965}
Bram Moolenaard04a0202016-01-26 23:30:18 +0100966# endif /* UNIX && !HAVE_SELECT */
Bram Moolenaare0874f82016-01-24 20:36:41 +0100967
Bram Moolenaarf12d9832016-01-29 21:11:25 +0100968# if (!defined(FEAT_GUI_W32) && defined(HAVE_SELECT)) || defined(PROTO)
Bram Moolenaare0874f82016-01-24 20:36:41 +0100969/*
970 * The type of "rfds" is hidden to avoid problems with the function proto.
971 */
972 int
973channel_select_setup(int maxfd_in, void *rfds_in)
974{
975 int maxfd = maxfd_in;
976 int i;
977 fd_set *rfds = rfds_in;
978
979 for (i = 0; i < channel_count; ++i)
980 if (channels[i].ch_fd >= 0)
981 {
982 FD_SET(channels[i].ch_fd, rfds);
983 if (maxfd < channels[i].ch_fd)
984 maxfd = channels[i].ch_fd;
985 }
986
987 return maxfd;
988}
989
990/*
991 * The type of "rfds" is hidden to avoid problems with the function proto.
992 */
993 int
994channel_select_check(int ret_in, void *rfds_in)
995{
996 int ret = ret_in;
997 int i;
998 fd_set *rfds = rfds_in;
999
1000 for (i = 0; i < channel_count; ++i)
1001 if (ret > 0 && channels[i].ch_fd >= 0
1002 && FD_ISSET(channels[i].ch_fd, rfds))
1003 {
1004 channel_read(i);
1005 --ret;
1006 }
1007
1008 return ret;
1009}
Bram Moolenaarf12d9832016-01-29 21:11:25 +01001010# endif /* !FEAT_GUI_W32 && HAVE_SELECT */
Bram Moolenaare0874f82016-01-24 20:36:41 +01001011
1012#endif /* FEAT_CHANNEL */