comparison src/channel.c @ 7770:42c1a4e63d12 v7.4.1182

commit https://github.com/vim/vim/commit/d04a020a8a8d7a438b091d49218c438880beb50c Author: Bram Moolenaar <Bram@vim.org> Date: Tue Jan 26 23:30:18 2016 +0100 patch 7.4.1182 Problem: Still socket code intertwined with netbeans. Solution: Move code from netbeans.c to channel.c
author Christian Brabandt <cb@256bit.org>
date Tue, 26 Jan 2016 23:45:05 +0100
parents 6069f43cea4e
children 0677c5b880d1
comparison
equal deleted inserted replaced
7769:3bdef7bd2244 7770:42c1a4e63d12
12 12
13 #include "vim.h" 13 #include "vim.h"
14 14
15 #if defined(FEAT_CHANNEL) || defined(PROTO) 15 #if defined(FEAT_CHANNEL) || defined(PROTO)
16 16
17 /*
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
26 static void cherror(char *fmt, char *arg);
27 static 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
68 extern HWND s_hwnd; /* Gvim's Window handle */
69 #endif
70
71 struct readqueue
72 {
73 char_u *buffer;
74 struct readqueue *next;
75 struct readqueue *prev;
76 };
77 typedef struct readqueue queue_T;
78
17 typedef struct { 79 typedef struct {
18 sock_T ch_fd; 80 sock_T ch_fd; /* the socket, -1 for a closed channel */
19 int ch_idx; 81 int ch_idx; /* used by channel_poll_setup() */
82 queue_T ch_head; /* dummy node, header for circular queue */
83
84 int ch_error; /* When TRUE an error was reported. Avoids giving
85 * 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
92 gint ch_inputHandler; /* Cookie for input */
93 #endif
94 #ifdef FEAT_GUI_W32
95 int ch_inputHandler = -1; /* simply ret.value of WSAAsyncSelect() */
96 #endif
97
98 void (*ch_close_cb)(void); /* callback invoked when channel is closed */
20 } channel_T; 99 } channel_T;
21 100
101 /*
102 * Information about all channels.
103 * There can be gaps for closed channels, they will be reused later.
104 */
22 static channel_T *channels = NULL; 105 static channel_T *channels = NULL;
23 static int channel_count = 0; 106 static int channel_count = 0;
24 107
25 /* 108 /*
109 * TODO: open debug file when desired.
110 */
111 FILE *debugfd = NULL;
112
113 /*
26 * Add a new channel slot, return the index. 114 * Add a new channel slot, return the index.
27 * Returns -1 if out of space. 115 * The channel isn't actually used into ch_fd is set >= 0;
116 * Returns -1 if all channels are in use.
28 */ 117 */
29 static int 118 static int
30 add_channel(void) 119 add_channel(void)
31 { 120 {
32 int idx; 121 int idx;
37 if (channels[idx].ch_fd < 0) 126 if (channels[idx].ch_fd < 0)
38 /* re-use a closed channel slot */ 127 /* re-use a closed channel slot */
39 return idx; 128 return idx;
40 if (channel_count == MAX_OPEN_CHANNELS) 129 if (channel_count == MAX_OPEN_CHANNELS)
41 return -1; 130 return -1;
42 new_channels = (channel_T *)alloc(sizeof(channel_T) * channel_count + 1); 131 new_channels = (channel_T *)alloc(sizeof(channel_T) * (channel_count + 1));
43 if (new_channels == NULL) 132 if (new_channels == NULL)
44 return -1; 133 return -1;
45 if (channels != NULL) 134 if (channels != NULL)
46 mch_memmove(new_channels, channels, sizeof(channel_T) * channel_count); 135 mch_memmove(new_channels, channels, sizeof(channel_T) * channel_count);
47 channels = new_channels; 136 channels = new_channels;
137 (void)vim_memset(&channels[channel_count], 0, sizeof(channel_T));
138
48 channels[channel_count].ch_fd = (sock_T)-1; 139 channels[channel_count].ch_fd = (sock_T)-1;
140 #ifdef FEAT_GUI_X11
141 channels[channel_count].ch_inputHandler = (XtInputId)NULL;
142 #endif
143 #ifdef FEAT_GUI_GTK
144 channels[channel_count].ch_inputHandler = 0;
145 #endif
146 #ifdef FEAT_GUI_W32
147 channels[channel_count].ch_inputHandler = -1;
148 #endif
49 149
50 return channel_count++; 150 return channel_count++;
51 } 151 }
52 152
53 #if defined(FEAT_NETBEANS_INTG) || defined(PROTO) 153 #if defined(FEAT_GUI) || defined(PROTO)
54 static int netbeans_channel = -1; 154 /*
55 155 * Read a command from netbeans.
56 /* 156 */
57 * Add the netbeans socket to the channels. 157 #ifdef FEAT_GUI_X11
58 * Return the channel index. 158 static void
159 messageFromNetbeans(XtPointer clientData,
160 int *unused1 UNUSED,
161 XtInputId *unused2 UNUSED)
162 {
163 channel_read((int)(long)clientData);
164 }
165 #endif
166
167 #ifdef FEAT_GUI_GTK
168 static void
169 messageFromNetbeans(gpointer clientData,
170 gint unused1 UNUSED,
171 GdkInputCondition unused2 UNUSED)
172 {
173 channel_read((int)(long)clientData);
174 }
175 #endif
176
177 static void
178 channel_gui_register(int idx)
179 {
180 channel_T *channel = &channels[idx];
181
182 if (!CH_HAS_GUI)
183 return;
184
185 # ifdef FEAT_GUI_X11
186 /* tell notifier we are interested in being called
187 * when there is input on the editor connection socket
188 */
189 if (channel->ch_inputHandler == (XtInputId)NULL)
190 channel->ch_inputHandler =
191 XtAppAddInput((XtAppContext)app_context, channel->ch_fd,
192 (XtPointer)(XtInputReadMask + XtInputExceptMask),
193 messageFromNetbeans, (XtPointer)idx);
194 # else
195 # ifdef FEAT_GUI_GTK
196 /*
197 * Tell gdk we are interested in being called when there
198 * is input on the editor connection socket
199 */
200 if (channel->ch_inputHandler == 0)
201 channel->ch_inputHandler =
202 gdk_input_add((gint)channel->ch_fd, (GdkInputCondition)
203 ((int)GDK_INPUT_READ + (int)GDK_INPUT_EXCEPTION),
204 messageFromNetbeans, (gpointer)(long)idx);
205 # else
206 # ifdef FEAT_GUI_W32
207 /*
208 * Tell Windows we are interested in receiving message when there
209 * is input on the editor connection socket.
210 * TODO: change WM_NETBEANS to something related to the channel index.
211 */
212 if (channel->ch_inputHandler == -1)
213 channel->ch_inputHandler =
214 WSAAsyncSelect(channel->ch_fd, s_hwnd, WM_NETBEANS, FD_READ);
215 # endif
216 # endif
217 # endif
218 }
219
220 /*
221 * Register any of our file descriptors with the GUI event handling system.
222 * Called when the GUI has started.
223 */
224 void
225 channel_gui_register_all(void)
226 {
227 int i;
228
229 for (i = 0; i < channel_count; ++i)
230 if (channels[i].ch_fd >= 0)
231 channel_gui_register(i);
232 }
233
234 static void
235 channel_gui_unregister(int idx)
236 {
237 channel_T *channel = &channels[idx];
238
239 # ifdef FEAT_GUI_X11
240 if (channel->ch_inputHandler != (XtInputId)NULL)
241 {
242 XtRemoveInput(channel->ch_inputHandler);
243 channel->ch_inputHandler = (XtInputId)NULL;
244 }
245 # else
246 # ifdef FEAT_GUI_GTK
247 if (channel->ch_inputHandler != 0)
248 {
249 gdk_input_remove(channel->ch_inputHandler);
250 channel->ch_inputHandler = 0;
251 }
252 # else
253 # ifdef FEAT_GUI_W32
254 if (channel->ch_inputHandler == 0)
255 {
256 WSAAsyncSelect(nbsock, s_hwnd, 0, 0);
257 channel->ch_inputHandler = -1;
258 }
259 # endif
260 # endif
261 # endif
262 }
263
264 #endif
265
266 /*
267 * Open a channel to "hostname":"port".
268 * Returns the channel number for success.
269 * Returns a negative number for failure.
59 */ 270 */
60 int 271 int
61 channel_add_netbeans(sock_T fd) 272 channel_open(char *hostname, int port_in, void (*close_cb)(void))
62 { 273 {
63 int idx = add_channel(); 274 int sd;
64 275 struct sockaddr_in server;
65 if (idx >= 0) 276 struct hostent * host;
66 { 277 #ifdef FEAT_GUI_W32
67 channels[idx].ch_fd = fd; 278 u_short port = port_in;
68 netbeans_channel = idx; 279 #else
69 } 280 int port = port_in;
281 #endif
282 int idx;
283
284 #ifdef FEAT_GUI_W32
285 channel_init_winsock();
286 #endif
287
288 idx = add_channel();
289 if (idx < 0)
290 {
291 CHERROR("All channels are in use\n", "");
292 EMSG(_("E999: All channels are in use"));
293 return -1;
294 }
295
296 if ((sd = (sock_T)socket(AF_INET, SOCK_STREAM, 0)) == (sock_T)-1)
297 {
298 CHERROR("error in socket() in channel_open()\n", "");
299 PERROR("E999: socket() in channel_open()");
300 return -1;
301 }
302
303 /* Get the server internet address and put into addr structure */
304 /* fill in the socket address structure and connect to server */
305 vim_memset((char *)&server, 0, sizeof(server));
306 server.sin_family = AF_INET;
307 server.sin_port = htons(port);
308 if ((host = gethostbyname(hostname)) == NULL)
309 {
310 CHERROR("error in gethostbyname() in channel_open()\n", "");
311 PERROR("E999: gethostbyname() in channel_open()");
312 sock_close(sd);
313 return -1;
314 }
315 memcpy((char *)&server.sin_addr, host->h_addr, host->h_length);
316
317 /* Connect to server */
318 if (connect(sd, (struct sockaddr *)&server, sizeof(server)))
319 {
320 SOCK_ERRNO;
321 CHERROR("channel_open: Connect failed with errno %d\n", errno);
322 if (errno == ECONNREFUSED)
323 {
324 sock_close(sd);
325 if ((sd = (sock_T)socket(AF_INET, SOCK_STREAM, 0)) == (sock_T)-1)
326 {
327 SOCK_ERRNO;
328 CHERROR("socket() retry in channel_open()\n", "");
329 PERROR("E999: socket() retry in channel_open()");
330 return -1;
331 }
332 if (connect(sd, (struct sockaddr *)&server, sizeof(server)))
333 {
334 int retries = 36;
335 int success = FALSE;
336
337 SOCK_ERRNO;
338 while (retries-- && ((errno == ECONNREFUSED)
339 || (errno == EINTR)))
340 {
341 CHERROR("retrying...\n", "");
342 mch_delay(3000L, TRUE);
343 ui_breakcheck();
344 if (got_int)
345 {
346 errno = EINTR;
347 break;
348 }
349 if (connect(sd, (struct sockaddr *)&server,
350 sizeof(server)) == 0)
351 {
352 success = TRUE;
353 break;
354 }
355 SOCK_ERRNO;
356 }
357 if (!success)
358 {
359 /* Get here when the server can't be found. */
360 CHERROR("Cannot connect to port after retry\n", "");
361 PERROR(_("E999: Cannot connect to port after retry2"));
362 sock_close(sd);
363 return -1;
364 }
365 }
366 }
367 else
368 {
369 CHERROR("Cannot connect to port\n", "");
370 PERROR(_("E999: Cannot connect to port"));
371 sock_close(sd);
372 return -1;
373 }
374 }
375
376 channels[idx].ch_fd = sd;
377 channels[idx].ch_close_cb = close_cb;
378
379 #ifdef FEAT_GUI
380 channel_gui_register(idx);
381 #endif
382
70 return idx; 383 return idx;
71 } 384 }
72 385
386 /*
387 * Return TRUE when channel "idx" is open.
388 */
389 int
390 channel_is_open(int idx)
391 {
392 return channels[idx].ch_fd >= 0;
393 }
394
395 /*
396 * Close channel "idx".
397 * This does not trigger the close callback.
398 */
73 void 399 void
74 channel_remove_netbeans() 400 channel_close(int idx)
75 { 401 {
76 channels[netbeans_channel].ch_fd = (sock_T)-1; 402 channel_T *channel = &channels[idx];
77 netbeans_channel = -1; 403
78 } 404 if (channel->ch_fd >= 0)
79 #endif 405 {
80 406 sock_close(channel->ch_fd);
81 static void 407 channel->ch_fd = -1;
408 #ifdef FEAT_GUI
409 channel_gui_unregister(idx);
410 #endif
411 }
412 }
413
414 /*
415 * Store "buf[len]" on channel "idx".
416 */
417 void
418 channel_save(int idx, char_u *buf, int len)
419 {
420 queue_T *node;
421 queue_T *head = &channels[idx].ch_head;
422
423 node = (queue_T *)alloc(sizeof(queue_T));
424 if (node == NULL)
425 return; /* out of memory */
426 node->buffer = alloc(len + 1);
427 if (node->buffer == NULL)
428 {
429 vim_free(node);
430 return; /* out of memory */
431 }
432 mch_memmove(node->buffer, buf, (size_t)len);
433 node->buffer[len] = NUL;
434
435 if (head->next == NULL) /* initialize circular queue */
436 {
437 head->next = head;
438 head->prev = head;
439 }
440
441 /* insert node at tail of queue */
442 node->next = head;
443 node->prev = head->prev;
444 head->prev->next = node;
445 head->prev = node;
446
447 if (debugfd != NULL)
448 {
449 fprintf(debugfd, "RECV on %d: ", idx);
450 fwrite(buf, len, 1, debugfd);
451 fprintf(debugfd, "\n");
452 }
453 }
454
455 /*
456 * Return the first buffer from the channel without removing it.
457 * Returns NULL if there is nothing.
458 */
459 char_u *
460 channel_peek(int idx)
461 {
462 queue_T *head = &channels[idx].ch_head;
463
464 if (head->next == head || head->next == NULL)
465 return NULL;
466 return head->next->buffer;
467 }
468
469 /*
470 * Return the first buffer from the channel and remove it.
471 * The caller must free it.
472 * Returns NULL if there is nothing.
473 */
474 char_u *
475 channel_get(int idx)
476 {
477 queue_T *head = &channels[idx].ch_head;
478 queue_T *node;
479 char_u *p;
480
481 if (head->next == head || head->next == NULL)
482 return NULL;
483 node = head->next;
484 /* dispose of the node but keep the buffer */
485 p = node->buffer;
486 head->next = node->next;
487 node->next->prev = node->prev;
488 vim_free(node);
489 return p;
490 }
491
492 /*
493 * Collapses the first and second buffer in the channel "idx".
494 * Returns FAIL if that is not possible.
495 */
496 int
497 channel_collapse(int idx)
498 {
499 queue_T *head = &channels[idx].ch_head;
500 queue_T *node = head->next;
501 char_u *p;
502
503 if (node == head || node == NULL || node->next == head)
504 return FAIL;
505
506 p = alloc((unsigned)(STRLEN(node->buffer)
507 + STRLEN(node->next->buffer) + 1));
508 if (p == NULL)
509 return FAIL; /* out of memory */
510 STRCPY(p, node->buffer);
511 STRCAT(p, node->next->buffer);
512 vim_free(node->next->buffer);
513 node->next->buffer = p;
514
515 /* dispose of the node and buffer */
516 head->next = node->next;
517 node->next->prev = node->prev;
518 vim_free(node->buffer);
519 vim_free(node);
520 return OK;
521 }
522
523 /*
524 * Clear the read buffer on channel "idx".
525 */
526 void
527 channel_clear(int idx)
528 {
529 queue_T *head = &channels[idx].ch_head;
530 queue_T *node = head->next;
531 queue_T *next;
532
533 while (node != NULL && node != head)
534 {
535 next = node->next;
536 vim_free(node->buffer);
537 vim_free(node);
538 if (next == head)
539 {
540 head->next = head;
541 head->prev = head;
542 break;
543 }
544 node = next;
545 }
546 }
547
548 /* Sent when the channel is found closed when reading. */
549 #define DETACH_MSG "\"DETACH\"\n"
550
551 /* Buffer size for reading incoming messages. */
552 #define MAXMSGSIZE 4096
553
554 /*
555 * Read from channel "idx". The data is put in the read queue.
556 */
557 void
82 channel_read(int idx) 558 channel_read(int idx)
83 { 559 {
84 # ifdef FEAT_NETBEANS_INTG 560 static char_u *buf = NULL;
85 if (idx == netbeans_channel) 561 int len = 0;
86 netbeans_read(); 562 int readlen = 0;
563 #ifdef HAVE_SELECT
564 struct timeval tval;
565 fd_set rfds;
566 #else
567 # ifdef HAVE_POLL
568 struct pollfd fds;
569 # endif
570 #endif
571 channel_T *channel = &channels[idx];
572
573 if (channel->ch_fd < 0)
574 {
575 CHLOG(idx, FALSE, "channel_read() called while socket is closed\n");
576 return;
577 }
578
579 /* Allocate a buffer to read into. */
580 if (buf == NULL)
581 {
582 buf = alloc(MAXMSGSIZE);
583 if (buf == NULL)
584 return; /* out of memory! */
585 }
586
587 /* Keep on reading for as long as there is something to read.
588 * Use select() or poll() to avoid blocking on a message that is exactly
589 * MAXMSGSIZE long. */
590 for (;;)
591 {
592 #ifdef HAVE_SELECT
593 FD_ZERO(&rfds);
594 FD_SET(channel->ch_fd, &rfds);
595 tval.tv_sec = 0;
596 tval.tv_usec = 0;
597 if (select(channel->ch_fd + 1, &rfds, NULL, NULL, &tval) <= 0)
598 break;
599 #else
600 # ifdef HAVE_POLL
601 fds.fd = channel->ch_fd;
602 fds.events = POLLIN;
603 if (poll(&fds, 1, 0) <= 0)
604 break;
605 # endif
606 #endif
607 len = sock_read(channel->ch_fd, buf, MAXMSGSIZE);
608 if (len <= 0)
609 break; /* error or nothing more to read */
610
611 /* Store the read message in the queue. */
612 channel_save(idx, buf, len);
613 readlen += len;
614 if (len < MAXMSGSIZE)
615 break; /* did read everything that's available */
616 }
617
618 /* Reading a socket disconnection (readlen == 0), or a socket error. */
619 if (readlen <= 0)
620 {
621 /* Queue a "DETACH" netbeans message in the command queue in order to
622 * terminate the netbeans session later. Do not end the session here
623 * directly as we may be running in the context of a call to
624 * netbeans_parse_messages():
625 * netbeans_parse_messages
626 * -> autocmd triggered while processing the netbeans cmd
627 * -> ui_breakcheck
628 * -> gui event loop or select loop
629 * -> channel_read()
630 */
631 channel_save(idx, (char_u *)DETACH_MSG, (int)STRLEN(DETACH_MSG));
632
633 channel_close(idx);
634 if (channel->ch_close_cb != NULL)
635 (*channel->ch_close_cb)();
636
637 if (len < 0)
638 {
639 /* Todo: which channel? */
640 CHERROR("%s(): cannot from channel\n", "channel_read");
641 PERROR(_("E999: read from channel"));
642 }
643 }
644
645 #if defined(CH_HAS_GUI) && defined(FEAT_GUI_GTK)
646 if (CH_HAS_GUI && gtk_main_level() > 0)
647 gtk_main_quit();
648 #endif
649 }
650
651 /*
652 * Write "buf" (NUL terminated string) to channel "idx".
653 * When "fun" is not NULL an error message might be given.
654 */
655 void
656 channel_send(int idx, char_u *buf, char *fun)
657 {
658 channel_T *channel = &channels[idx];
659 int len = (int)STRLEN(buf);
660
661 if (channel->ch_fd < 0)
662 {
663 if (!channel->ch_error && fun != NULL)
664 {
665 CHERROR(" %s(): write while not connected\n", fun);
666 EMSG2("E630: %s(): write while not connected", fun);
667 }
668 channel->ch_error = TRUE;
669 }
670 else if (sock_write(channel->ch_fd, buf, len) != len)
671 {
672 if (!channel->ch_error && fun != NULL)
673 {
674 CHERROR(" %s(): write failed\n", fun);
675 EMSG2("E631: %s(): write failed", fun);
676 }
677 channel->ch_error = TRUE;
678 }
87 else 679 else
88 # endif 680 channel->ch_error = FALSE;
89 { 681 }
90 ; /* TODO: read */ 682
91 } 683 # if (defined(UNIX) && !defined(HAVE_SELECT)) || defined(PROTO)
92 }
93
94 #if (defined(UNIX) && !defined(HAVE_SELECT)) || defined(PROTO)
95 /* 684 /*
96 * Add open channels to the poll struct. 685 * Add open channels to the poll struct.
97 * Return the adjusted struct index. 686 * Return the adjusted struct index.
98 * The type of "fds" is hidden to avoid problems with the function proto. 687 * The type of "fds" is hidden to avoid problems with the function proto.
99 */ 688 */
136 --ret; 725 --ret;
137 } 726 }
138 727
139 return ret; 728 return ret;
140 } 729 }
141 #endif /* UNIX && !HAVE_SELECT */ 730 # endif /* UNIX && !HAVE_SELECT */
142 731
143 #if (defined(UNIX) && defined(HAVE_SELECT)) || defined(PROTO) 732 # if (defined(UNIX) && defined(HAVE_SELECT)) || defined(PROTO)
144 /* 733 /*
145 * The type of "rfds" is hidden to avoid problems with the function proto. 734 * The type of "rfds" is hidden to avoid problems with the function proto.
146 */ 735 */
147 int 736 int
148 channel_select_setup(int maxfd_in, void *rfds_in) 737 channel_select_setup(int maxfd_in, void *rfds_in)
180 --ret; 769 --ret;
181 } 770 }
182 771
183 return ret; 772 return ret;
184 } 773 }
185 #endif /* UNIX && HAVE_SELECT */ 774 # endif /* UNIX && HAVE_SELECT */
186 775
187 #endif /* FEAT_CHANNEL */ 776 #endif /* FEAT_CHANNEL */