blob: 952123c539a3dec3b6b84cd2b3eb3869bc023f8e [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
94#ifdef FEAT_GUI_W32
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;
282#ifdef FEAT_GUI_W32
283 u_short port = port_in;
284#else
285 int port = port_in;
286#endif
287 int idx;
288
289#ifdef FEAT_GUI_W32
290 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".
563 */
564 void
565channel_save(int idx, char_u *buf, int len)
566{
567 queue_T *node;
568 queue_T *head = &channels[idx].ch_head;
569
570 node = (queue_T *)alloc(sizeof(queue_T));
571 if (node == NULL)
572 return; /* out of memory */
573 node->buffer = alloc(len + 1);
574 if (node->buffer == NULL)
575 {
576 vim_free(node);
577 return; /* out of memory */
578 }
579 mch_memmove(node->buffer, buf, (size_t)len);
580 node->buffer[len] = NUL;
581
582 if (head->next == NULL) /* initialize circular queue */
583 {
584 head->next = head;
585 head->prev = head;
586 }
587
588 /* insert node at tail of queue */
589 node->next = head;
590 node->prev = head->prev;
591 head->prev->next = node;
592 head->prev = node;
593
594 if (debugfd != NULL)
595 {
596 fprintf(debugfd, "RECV on %d: ", idx);
597 fwrite(buf, len, 1, debugfd);
598 fprintf(debugfd, "\n");
599 }
600}
601
602/*
603 * Return the first buffer from the channel without removing it.
604 * Returns NULL if there is nothing.
605 */
606 char_u *
607channel_peek(int idx)
608{
609 queue_T *head = &channels[idx].ch_head;
610
611 if (head->next == head || head->next == NULL)
612 return NULL;
613 return head->next->buffer;
614}
615
616/*
617 * Return the first buffer from the channel and remove it.
618 * The caller must free it.
619 * Returns NULL if there is nothing.
620 */
621 char_u *
622channel_get(int idx)
623{
624 queue_T *head = &channels[idx].ch_head;
625 queue_T *node;
626 char_u *p;
627
628 if (head->next == head || head->next == NULL)
629 return NULL;
630 node = head->next;
631 /* dispose of the node but keep the buffer */
632 p = node->buffer;
633 head->next = node->next;
634 node->next->prev = node->prev;
635 vim_free(node);
636 return p;
637}
638
639/*
640 * Collapses the first and second buffer in the channel "idx".
641 * Returns FAIL if that is not possible.
642 */
643 int
644channel_collapse(int idx)
645{
646 queue_T *head = &channels[idx].ch_head;
647 queue_T *node = head->next;
648 char_u *p;
649
650 if (node == head || node == NULL || node->next == head)
651 return FAIL;
652
653 p = alloc((unsigned)(STRLEN(node->buffer)
654 + STRLEN(node->next->buffer) + 1));
655 if (p == NULL)
656 return FAIL; /* out of memory */
657 STRCPY(p, node->buffer);
658 STRCAT(p, node->next->buffer);
659 vim_free(node->next->buffer);
660 node->next->buffer = p;
661
662 /* dispose of the node and buffer */
663 head->next = node->next;
664 node->next->prev = node->prev;
665 vim_free(node->buffer);
666 vim_free(node);
667 return OK;
668}
669
670/*
671 * Clear the read buffer on channel "idx".
672 */
673 void
674channel_clear(int idx)
675{
676 queue_T *head = &channels[idx].ch_head;
677 queue_T *node = head->next;
678 queue_T *next;
679
680 while (node != NULL && node != head)
681 {
682 next = node->next;
683 vim_free(node->buffer);
684 vim_free(node);
685 if (next == head)
686 {
687 head->next = head;
688 head->prev = head;
689 break;
690 }
691 node = next;
692 }
693}
694
695/* Sent when the channel is found closed when reading. */
696#define DETACH_MSG "\"DETACH\"\n"
697
698/* Buffer size for reading incoming messages. */
699#define MAXMSGSIZE 4096
700
701/*
Bram Moolenaar3b5f9292016-01-28 22:37:01 +0100702 * Check for reading from "fd" with "timeout" msec.
703 * Return FAIL when there is nothing to read.
704 */
705 static int
706channel_wait(int fd, int timeout)
707{
708#ifdef HAVE_SELECT
709 struct timeval tval;
710 fd_set rfds;
711 int ret;
712
713 FD_ZERO(&rfds);
714 FD_SET(fd, &rfds);
715 tval.tv_sec = timeout / 1000;
716 tval.tv_usec = (timeout % 1000) * 1000;
717 for (;;)
718 {
719 ret = select(fd + 1, &rfds, NULL, NULL, &tval);
720# ifdef EINTR
721 if (ret == -1 && errno == EINTR)
722 continue;
723# endif
724 if (ret <= 0)
725 return FAIL;
726 break;
727 }
728#else
729 struct pollfd fds;
730
731 fds.fd = fd;
732 fds.events = POLLIN;
733 if (poll(&fds, 1, timeout) <= 0)
734 return FAIL;
735#endif
736 return OK;
737}
738
739/*
740 * Return a unique ID to be used in a message.
741 */
742 int
743channel_get_id()
744{
745 static int next_id = 1;
746
747 return next_id++;
748}
749
750/*
751 * Read from channel "idx" for as long as there is something to read.
752 * The data is put in the read queue.
Bram Moolenaard04a0202016-01-26 23:30:18 +0100753 */
754 void
755channel_read(int idx)
756{
757 static char_u *buf = NULL;
758 int len = 0;
759 int readlen = 0;
Bram Moolenaard04a0202016-01-26 23:30:18 +0100760 channel_T *channel = &channels[idx];
761
762 if (channel->ch_fd < 0)
763 {
764 CHLOG(idx, FALSE, "channel_read() called while socket is closed\n");
765 return;
766 }
767
768 /* Allocate a buffer to read into. */
769 if (buf == NULL)
770 {
771 buf = alloc(MAXMSGSIZE);
772 if (buf == NULL)
773 return; /* out of memory! */
774 }
775
776 /* Keep on reading for as long as there is something to read.
777 * Use select() or poll() to avoid blocking on a message that is exactly
778 * MAXMSGSIZE long. */
779 for (;;)
780 {
Bram Moolenaar3b5f9292016-01-28 22:37:01 +0100781 if (channel_wait(channel->ch_fd, 0) == FAIL)
Bram Moolenaard04a0202016-01-26 23:30:18 +0100782 break;
Bram Moolenaard04a0202016-01-26 23:30:18 +0100783 len = sock_read(channel->ch_fd, buf, MAXMSGSIZE);
784 if (len <= 0)
785 break; /* error or nothing more to read */
786
787 /* Store the read message in the queue. */
788 channel_save(idx, buf, len);
789 readlen += len;
790 if (len < MAXMSGSIZE)
791 break; /* did read everything that's available */
792 }
793
794 /* Reading a socket disconnection (readlen == 0), or a socket error. */
795 if (readlen <= 0)
796 {
797 /* Queue a "DETACH" netbeans message in the command queue in order to
798 * terminate the netbeans session later. Do not end the session here
799 * directly as we may be running in the context of a call to
800 * netbeans_parse_messages():
801 * netbeans_parse_messages
802 * -> autocmd triggered while processing the netbeans cmd
803 * -> ui_breakcheck
804 * -> gui event loop or select loop
805 * -> channel_read()
806 */
807 channel_save(idx, (char_u *)DETACH_MSG, (int)STRLEN(DETACH_MSG));
808
809 channel_close(idx);
810 if (channel->ch_close_cb != NULL)
811 (*channel->ch_close_cb)();
812
813 if (len < 0)
814 {
815 /* Todo: which channel? */
816 CHERROR("%s(): cannot from channel\n", "channel_read");
817 PERROR(_("E999: read from channel"));
818 }
819 }
820
Bram Moolenaar3b5f9292016-01-28 22:37:01 +0100821 may_invoke_callback(idx);
822
Bram Moolenaard04a0202016-01-26 23:30:18 +0100823#if defined(CH_HAS_GUI) && defined(FEAT_GUI_GTK)
824 if (CH_HAS_GUI && gtk_main_level() > 0)
825 gtk_main_quit();
826#endif
827}
828
Bram Moolenaar3b5f9292016-01-28 22:37:01 +0100829/*
830 * Read from channel "idx". Blocks until there is something to read or the
831 * timeout expires.
832 * Returns what was read in allocated memory.
833 * Returns NULL in case of error or timeout.
834 */
835 char_u *
836channel_read_block(int idx)
837{
838 if (channel_peek(idx) == NULL)
839 {
840 /* Wait for up to 2 seconds.
841 * TODO: use timeout set on the channel. */
842 if (channel_wait(channels[idx].ch_fd, 2000) == FAIL)
843 {
844 channels[idx].ch_will_block = FALSE;
845 return NULL;
846 }
847 channel_read(idx);
848 }
849
850 /* Concatenate everything into one buffer.
851 * TODO: avoid multiple allocations. */
852 while (channel_collapse(idx) == OK)
853 ;
854
855 channels[idx].ch_will_block = FALSE;
856 return channel_get(idx);
857}
858
Bram Moolenaar85be35f2016-01-27 21:08:18 +0100859# if defined(FEAT_GUI_W32) || defined(PROTO)
860/*
861 * Lookup the channel index from the socket.
862 * Returns -1 when the socket isn't found.
863 */
864 int
865channel_socket2idx(sock_T fd)
866{
867 int i;
868
869 if (fd >= 0)
870 for (i = 0; i < channel_count; ++i)
871 if (channels[i].ch_fd == fd)
872 return i;
873 return -1;
874}
875# endif
876
Bram Moolenaard04a0202016-01-26 23:30:18 +0100877/*
878 * Write "buf" (NUL terminated string) to channel "idx".
879 * When "fun" is not NULL an error message might be given.
Bram Moolenaar3b5f9292016-01-28 22:37:01 +0100880 * Return FAIL or OK.
Bram Moolenaard04a0202016-01-26 23:30:18 +0100881 */
Bram Moolenaar3b5f9292016-01-28 22:37:01 +0100882 int
Bram Moolenaard04a0202016-01-26 23:30:18 +0100883channel_send(int idx, char_u *buf, char *fun)
884{
885 channel_T *channel = &channels[idx];
886 int len = (int)STRLEN(buf);
887
888 if (channel->ch_fd < 0)
889 {
890 if (!channel->ch_error && fun != NULL)
891 {
892 CHERROR(" %s(): write while not connected\n", fun);
893 EMSG2("E630: %s(): write while not connected", fun);
894 }
895 channel->ch_error = TRUE;
Bram Moolenaar3b5f9292016-01-28 22:37:01 +0100896 return FAIL;
Bram Moolenaard04a0202016-01-26 23:30:18 +0100897 }
Bram Moolenaar3b5f9292016-01-28 22:37:01 +0100898
899 if (sock_write(channel->ch_fd, buf, len) != len)
Bram Moolenaard04a0202016-01-26 23:30:18 +0100900 {
901 if (!channel->ch_error && fun != NULL)
902 {
903 CHERROR(" %s(): write failed\n", fun);
904 EMSG2("E631: %s(): write failed", fun);
905 }
906 channel->ch_error = TRUE;
Bram Moolenaar3b5f9292016-01-28 22:37:01 +0100907 return FAIL;
Bram Moolenaard04a0202016-01-26 23:30:18 +0100908 }
Bram Moolenaar3b5f9292016-01-28 22:37:01 +0100909
910 channel->ch_error = FALSE;
911 return OK;
Bram Moolenaard04a0202016-01-26 23:30:18 +0100912}
913
914# if (defined(UNIX) && !defined(HAVE_SELECT)) || defined(PROTO)
Bram Moolenaare0874f82016-01-24 20:36:41 +0100915/*
916 * Add open channels to the poll struct.
917 * Return the adjusted struct index.
918 * The type of "fds" is hidden to avoid problems with the function proto.
919 */
920 int
921channel_poll_setup(int nfd_in, void *fds_in)
922{
923 int nfd = nfd_in;
924 int i;
925 struct pollfd *fds = fds_in;
926
927 for (i = 0; i < channel_count; ++i)
928 if (channels[i].ch_fd >= 0)
929 {
930 channels[i].ch_idx = nfd;
931 fds[nfd].fd = channels[i].ch_fd;
932 fds[nfd].events = POLLIN;
933 nfd++;
934 }
935 else
936 channels[i].ch_idx = -1;
937
938 return nfd;
939}
940
941/*
942 * The type of "fds" is hidden to avoid problems with the function proto.
943 */
944 int
945channel_poll_check(int ret_in, void *fds_in)
946{
947 int ret = ret_in;
948 int i;
949 struct pollfd *fds = fds_in;
950
951 for (i = 0; i < channel_count; ++i)
952 if (ret > 0 && channels[i].ch_idx != -1
953 && fds[channels[i].ch_idx].revents & POLLIN)
954 {
955 channel_read(i);
956 --ret;
957 }
958
959 return ret;
960}
Bram Moolenaard04a0202016-01-26 23:30:18 +0100961# endif /* UNIX && !HAVE_SELECT */
Bram Moolenaare0874f82016-01-24 20:36:41 +0100962
Bram Moolenaard04a0202016-01-26 23:30:18 +0100963# if (defined(UNIX) && defined(HAVE_SELECT)) || defined(PROTO)
Bram Moolenaare0874f82016-01-24 20:36:41 +0100964/*
965 * The type of "rfds" is hidden to avoid problems with the function proto.
966 */
967 int
968channel_select_setup(int maxfd_in, void *rfds_in)
969{
970 int maxfd = maxfd_in;
971 int i;
972 fd_set *rfds = rfds_in;
973
974 for (i = 0; i < channel_count; ++i)
975 if (channels[i].ch_fd >= 0)
976 {
977 FD_SET(channels[i].ch_fd, rfds);
978 if (maxfd < channels[i].ch_fd)
979 maxfd = channels[i].ch_fd;
980 }
981
982 return maxfd;
983}
984
985/*
986 * The type of "rfds" is hidden to avoid problems with the function proto.
987 */
988 int
989channel_select_check(int ret_in, void *rfds_in)
990{
991 int ret = ret_in;
992 int i;
993 fd_set *rfds = rfds_in;
994
995 for (i = 0; i < channel_count; ++i)
996 if (ret > 0 && channels[i].ch_fd >= 0
997 && FD_ISSET(channels[i].ch_fd, rfds))
998 {
999 channel_read(i);
1000 --ret;
1001 }
1002
1003 return ret;
1004}
Bram Moolenaard04a0202016-01-26 23:30:18 +01001005# endif /* UNIX && HAVE_SELECT */
Bram Moolenaare0874f82016-01-24 20:36:41 +01001006
1007#endif /* FEAT_CHANNEL */