blob: c18f25e2634721198c2374e9a058ad95e9f00be4 [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
Bram Moolenaarb8b65112016-01-28 23:01:49 +0100729# ifdef HAVE_POLL
Bram Moolenaar3b5f9292016-01-28 22:37:01 +0100730 struct pollfd fds;
731
732 fds.fd = fd;
733 fds.events = POLLIN;
734 if (poll(&fds, 1, timeout) <= 0)
735 return FAIL;
Bram Moolenaarb8b65112016-01-28 23:01:49 +0100736# endif
Bram Moolenaar3b5f9292016-01-28 22:37:01 +0100737#endif
738 return OK;
739}
740
741/*
742 * Return a unique ID to be used in a message.
743 */
744 int
745channel_get_id()
746{
747 static int next_id = 1;
748
749 return next_id++;
750}
751
752/*
753 * Read from channel "idx" for as long as there is something to read.
754 * The data is put in the read queue.
Bram Moolenaard04a0202016-01-26 23:30:18 +0100755 */
756 void
757channel_read(int idx)
758{
759 static char_u *buf = NULL;
760 int len = 0;
761 int readlen = 0;
Bram Moolenaard04a0202016-01-26 23:30:18 +0100762 channel_T *channel = &channels[idx];
763
764 if (channel->ch_fd < 0)
765 {
766 CHLOG(idx, FALSE, "channel_read() called while socket is closed\n");
767 return;
768 }
769
770 /* Allocate a buffer to read into. */
771 if (buf == NULL)
772 {
773 buf = alloc(MAXMSGSIZE);
774 if (buf == NULL)
775 return; /* out of memory! */
776 }
777
778 /* Keep on reading for as long as there is something to read.
779 * Use select() or poll() to avoid blocking on a message that is exactly
780 * MAXMSGSIZE long. */
781 for (;;)
782 {
Bram Moolenaar3b5f9292016-01-28 22:37:01 +0100783 if (channel_wait(channel->ch_fd, 0) == FAIL)
Bram Moolenaard04a0202016-01-26 23:30:18 +0100784 break;
Bram Moolenaard04a0202016-01-26 23:30:18 +0100785 len = sock_read(channel->ch_fd, buf, MAXMSGSIZE);
786 if (len <= 0)
787 break; /* error or nothing more to read */
788
789 /* Store the read message in the queue. */
790 channel_save(idx, buf, len);
791 readlen += len;
792 if (len < MAXMSGSIZE)
793 break; /* did read everything that's available */
794 }
795
796 /* Reading a socket disconnection (readlen == 0), or a socket error. */
797 if (readlen <= 0)
798 {
799 /* Queue a "DETACH" netbeans message in the command queue in order to
800 * terminate the netbeans session later. Do not end the session here
801 * directly as we may be running in the context of a call to
802 * netbeans_parse_messages():
803 * netbeans_parse_messages
804 * -> autocmd triggered while processing the netbeans cmd
805 * -> ui_breakcheck
806 * -> gui event loop or select loop
807 * -> channel_read()
808 */
809 channel_save(idx, (char_u *)DETACH_MSG, (int)STRLEN(DETACH_MSG));
810
811 channel_close(idx);
812 if (channel->ch_close_cb != NULL)
813 (*channel->ch_close_cb)();
814
815 if (len < 0)
816 {
817 /* Todo: which channel? */
818 CHERROR("%s(): cannot from channel\n", "channel_read");
819 PERROR(_("E999: read from channel"));
820 }
821 }
822
Bram Moolenaar3b5f9292016-01-28 22:37:01 +0100823 may_invoke_callback(idx);
824
Bram Moolenaard04a0202016-01-26 23:30:18 +0100825#if defined(CH_HAS_GUI) && defined(FEAT_GUI_GTK)
826 if (CH_HAS_GUI && gtk_main_level() > 0)
827 gtk_main_quit();
828#endif
829}
830
Bram Moolenaar3b5f9292016-01-28 22:37:01 +0100831/*
832 * Read from channel "idx". Blocks until there is something to read or the
833 * timeout expires.
834 * Returns what was read in allocated memory.
835 * Returns NULL in case of error or timeout.
836 */
837 char_u *
838channel_read_block(int idx)
839{
840 if (channel_peek(idx) == NULL)
841 {
842 /* Wait for up to 2 seconds.
843 * TODO: use timeout set on the channel. */
844 if (channel_wait(channels[idx].ch_fd, 2000) == FAIL)
845 {
846 channels[idx].ch_will_block = FALSE;
847 return NULL;
848 }
849 channel_read(idx);
850 }
851
852 /* Concatenate everything into one buffer.
853 * TODO: avoid multiple allocations. */
854 while (channel_collapse(idx) == OK)
855 ;
856
857 channels[idx].ch_will_block = FALSE;
858 return channel_get(idx);
859}
860
Bram Moolenaar85be35f2016-01-27 21:08:18 +0100861# if defined(FEAT_GUI_W32) || defined(PROTO)
862/*
863 * Lookup the channel index from the socket.
864 * Returns -1 when the socket isn't found.
865 */
866 int
867channel_socket2idx(sock_T fd)
868{
869 int i;
870
871 if (fd >= 0)
872 for (i = 0; i < channel_count; ++i)
873 if (channels[i].ch_fd == fd)
874 return i;
875 return -1;
876}
877# endif
878
Bram Moolenaard04a0202016-01-26 23:30:18 +0100879/*
880 * Write "buf" (NUL terminated string) to channel "idx".
881 * When "fun" is not NULL an error message might be given.
Bram Moolenaar3b5f9292016-01-28 22:37:01 +0100882 * Return FAIL or OK.
Bram Moolenaard04a0202016-01-26 23:30:18 +0100883 */
Bram Moolenaar3b5f9292016-01-28 22:37:01 +0100884 int
Bram Moolenaard04a0202016-01-26 23:30:18 +0100885channel_send(int idx, char_u *buf, char *fun)
886{
887 channel_T *channel = &channels[idx];
888 int len = (int)STRLEN(buf);
889
890 if (channel->ch_fd < 0)
891 {
892 if (!channel->ch_error && fun != NULL)
893 {
894 CHERROR(" %s(): write while not connected\n", fun);
895 EMSG2("E630: %s(): write while not connected", fun);
896 }
897 channel->ch_error = TRUE;
Bram Moolenaar3b5f9292016-01-28 22:37:01 +0100898 return FAIL;
Bram Moolenaard04a0202016-01-26 23:30:18 +0100899 }
Bram Moolenaar3b5f9292016-01-28 22:37:01 +0100900
901 if (sock_write(channel->ch_fd, buf, len) != len)
Bram Moolenaard04a0202016-01-26 23:30:18 +0100902 {
903 if (!channel->ch_error && fun != NULL)
904 {
905 CHERROR(" %s(): write failed\n", fun);
906 EMSG2("E631: %s(): write failed", fun);
907 }
908 channel->ch_error = TRUE;
Bram Moolenaar3b5f9292016-01-28 22:37:01 +0100909 return FAIL;
Bram Moolenaard04a0202016-01-26 23:30:18 +0100910 }
Bram Moolenaar3b5f9292016-01-28 22:37:01 +0100911
912 channel->ch_error = FALSE;
913 return OK;
Bram Moolenaard04a0202016-01-26 23:30:18 +0100914}
915
916# if (defined(UNIX) && !defined(HAVE_SELECT)) || defined(PROTO)
Bram Moolenaare0874f82016-01-24 20:36:41 +0100917/*
918 * Add open channels to the poll struct.
919 * Return the adjusted struct index.
920 * The type of "fds" is hidden to avoid problems with the function proto.
921 */
922 int
923channel_poll_setup(int nfd_in, void *fds_in)
924{
925 int nfd = nfd_in;
926 int i;
927 struct pollfd *fds = fds_in;
928
929 for (i = 0; i < channel_count; ++i)
930 if (channels[i].ch_fd >= 0)
931 {
932 channels[i].ch_idx = nfd;
933 fds[nfd].fd = channels[i].ch_fd;
934 fds[nfd].events = POLLIN;
935 nfd++;
936 }
937 else
938 channels[i].ch_idx = -1;
939
940 return nfd;
941}
942
943/*
944 * The type of "fds" is hidden to avoid problems with the function proto.
945 */
946 int
947channel_poll_check(int ret_in, void *fds_in)
948{
949 int ret = ret_in;
950 int i;
951 struct pollfd *fds = fds_in;
952
953 for (i = 0; i < channel_count; ++i)
954 if (ret > 0 && channels[i].ch_idx != -1
955 && fds[channels[i].ch_idx].revents & POLLIN)
956 {
957 channel_read(i);
958 --ret;
959 }
960
961 return ret;
962}
Bram Moolenaard04a0202016-01-26 23:30:18 +0100963# endif /* UNIX && !HAVE_SELECT */
Bram Moolenaare0874f82016-01-24 20:36:41 +0100964
Bram Moolenaard04a0202016-01-26 23:30:18 +0100965# if (defined(UNIX) && defined(HAVE_SELECT)) || defined(PROTO)
Bram Moolenaare0874f82016-01-24 20:36:41 +0100966/*
967 * The type of "rfds" is hidden to avoid problems with the function proto.
968 */
969 int
970channel_select_setup(int maxfd_in, void *rfds_in)
971{
972 int maxfd = maxfd_in;
973 int i;
974 fd_set *rfds = rfds_in;
975
976 for (i = 0; i < channel_count; ++i)
977 if (channels[i].ch_fd >= 0)
978 {
979 FD_SET(channels[i].ch_fd, rfds);
980 if (maxfd < channels[i].ch_fd)
981 maxfd = channels[i].ch_fd;
982 }
983
984 return maxfd;
985}
986
987/*
988 * The type of "rfds" is hidden to avoid problems with the function proto.
989 */
990 int
991channel_select_check(int ret_in, void *rfds_in)
992{
993 int ret = ret_in;
994 int i;
995 fd_set *rfds = rfds_in;
996
997 for (i = 0; i < channel_count; ++i)
998 if (ret > 0 && channels[i].ch_fd >= 0
999 && FD_ISSET(channels[i].ch_fd, rfds))
1000 {
1001 channel_read(i);
1002 --ret;
1003 }
1004
1005 return ret;
1006}
Bram Moolenaard04a0202016-01-26 23:30:18 +01001007# endif /* UNIX && HAVE_SELECT */
Bram Moolenaare0874f82016-01-24 20:36:41 +01001008
1009#endif /* FEAT_CHANNEL */