To: vim_dev@googlegroups.com Subject: Patch 7.4.1351 Fcc: outbox From: Bram Moolenaar Mime-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ------------ Patch 7.4.1351 Problem: When the port isn't opened yet when ch_open() is called it may fail instead of waiting for the specified time. Solution: Loop when select() succeeds but when connect() failed. Also use channel logging for jobs. Add ch_log(). Files: src/channel.c, src/eval.c, src/netbeans.c, src/proto/channel.pro, src/testdir/test_channel.vim, src/testdir/test_channel.py *** ../vim-7.4.1350/src/channel.c 2016-02-16 22:01:23.822490218 +0100 --- src/channel.c 2016-02-18 22:14:01.995469291 +0100 *************** *** 90,95 **** --- 90,98 ---- /* Log file opened with ch_logfile(). */ static FILE *log_fd = NULL; + #ifdef FEAT_RELTIME + static proftime_T log_start; + #endif void ch_logfile(FILE *file) *************** *** 98,104 **** --- 101,118 ---- fclose(log_fd); log_fd = file; if (log_fd != NULL) + { fprintf(log_fd, "==== start log session ====\n"); + #ifdef FEAT_RELTIME + profile_start(&log_start); + #endif + } + } + + int + ch_log_active() + { + return log_fd != NULL; } static void *************** *** 106,111 **** --- 120,132 ---- { if (log_fd != NULL) { + #ifdef FEAT_RELTIME + proftime_T log_now; + + profile_start(&log_now); + profile_sub(&log_now, &log_start); + fprintf(log_fd, "%s ", profile_msg(&log_now)); + #endif if (ch != NULL) fprintf(log_fd, "%son %d: ", what, ch->ch_id); else *************** *** 113,125 **** } } ! static void ch_log(channel_T *ch, char *msg) { if (log_fd != NULL) { ch_log_lead("", ch); fputs(msg, log_fd); fflush(log_fd); } } --- 134,147 ---- } } ! void ch_log(channel_T *ch, char *msg) { if (log_fd != NULL) { ch_log_lead("", ch); fputs(msg, log_fd); + fputc('\n', log_fd); fflush(log_fd); } } *************** *** 131,147 **** { ch_log_lead("", ch); fprintf(log_fd, msg, nr); fflush(log_fd); } } ! static void ch_logs(channel_T *ch, char *msg, char *name) { if (log_fd != NULL) { ch_log_lead("", ch); fprintf(log_fd, msg, name); fflush(log_fd); } } --- 153,171 ---- { ch_log_lead("", ch); fprintf(log_fd, msg, nr); + fputc('\n', log_fd); fflush(log_fd); } } ! void ch_logs(channel_T *ch, char *msg, char *name) { if (log_fd != NULL) { ch_log_lead("", ch); fprintf(log_fd, msg, name); + fputc('\n', log_fd); fflush(log_fd); } } *************** *** 153,158 **** --- 177,183 ---- { ch_log_lead("", ch); fprintf(log_fd, msg, name, nr); + fputc('\n', log_fd); fflush(log_fd); } } *************** *** 164,169 **** --- 189,195 ---- { ch_log_lead("ERR ", ch); fputs(msg, log_fd); + fputc('\n', log_fd); fflush(log_fd); } } *************** *** 175,180 **** --- 201,207 ---- { ch_log_lead("ERR ", ch); fprintf(log_fd, msg, nr); + fputc('\n', log_fd); fflush(log_fd); } } *************** *** 186,191 **** --- 213,219 ---- { ch_log_lead("ERR ", ch); fprintf(log_fd, msg, arg); + fputc('\n', log_fd); fflush(log_fd); } } *************** *** 253,259 **** return NULL; channel->ch_id = next_ch_id++; ! ch_log(channel, "Created channel\n"); #ifdef CHANNEL_PIPES for (which = CHAN_SOCK; which <= CHAN_IN; ++which) --- 281,287 ---- return NULL; channel->ch_id = next_ch_id++; ! ch_log(channel, "Created channel"); #ifdef CHANNEL_PIPES for (which = CHAN_SOCK; which <= CHAN_IN; ++which) *************** *** 470,483 **** channel_T * channel_open(char *hostname, int port_in, int waittime, void (*close_cb)(void)) { ! int sd; struct sockaddr_in server; ! struct hostent * host; #ifdef WIN32 u_short port = port_in; u_long val = 1; #else int port = port_in; #endif channel_T *channel; int ret; --- 498,514 ---- channel_T * channel_open(char *hostname, int port_in, int waittime, void (*close_cb)(void)) { ! int sd = -1; struct sockaddr_in server; ! struct hostent *host; #ifdef WIN32 u_short port = port_in; u_long val = 1; #else int port = port_in; + struct timeval start_tv; + int so_error; + socklen_t so_error_len = sizeof(so_error); #endif channel_T *channel; int ret; *************** *** 489,504 **** channel = add_channel(); if (channel == NULL) { ! ch_error(NULL, "Cannot allocate channel.\n"); ! EMSG(_("E897: All channels are in use")); ! return NULL; ! } ! ! if ((sd = socket(AF_INET, SOCK_STREAM, 0)) == -1) ! { ! ch_error(channel, "in socket() in channel_open().\n"); ! PERROR("E898: socket() in channel_open()"); ! channel_free(channel); return NULL; } --- 520,526 ---- channel = add_channel(); if (channel == NULL) { ! ch_error(NULL, "Cannot allocate channel."); return NULL; } *************** *** 509,623 **** server.sin_port = htons(port); if ((host = gethostbyname(hostname)) == NULL) { ! ch_error(channel, "in gethostbyname() in channel_open()\n"); PERROR("E901: gethostbyname() in channel_open()"); - sock_close(sd); channel_free(channel); return NULL; } memcpy((char *)&server.sin_addr, host->h_addr, host->h_length); ! if (waittime >= 0) ! { ! /* Make connect non-blocking. */ ! if ( ! #ifdef _WIN32 ! ioctlsocket(sd, FIONBIO, &val) < 0 ! #else ! fcntl(sd, F_SETFL, O_NONBLOCK) < 0 #endif ! ) ! { ! SOCK_ERRNO; ! ch_errorn(channel, "channel_open: Connect failed with errno %d\n", ! errno); sock_close(sd); channel_free(channel); return NULL; } - } ! /* Try connecting to the server. */ ! ch_logsn(channel, "Connecting to %s port %d\n", hostname, port); ! ret = connect(sd, (struct sockaddr *)&server, sizeof(server)); ! SOCK_ERRNO; ! if (ret < 0) ! { ! if (errno != EWOULDBLOCK #ifdef EINPROGRESS && errno != EINPROGRESS #endif ! ) ! { ! ch_errorn(channel, "channel_open: Connect failed with errno %d\n", ! errno); ! PERROR(_(e_cannot_connect)); ! sock_close(sd); ! channel_free(channel); ! return NULL; } - } ! if (waittime >= 0 && ret < 0) ! { ! struct timeval tv; ! fd_set wfds; #if defined(__APPLE__) && __APPLE__ == 1 # define PASS_RFDS ! fd_set rfds; ! FD_ZERO(&rfds); ! FD_SET(sd, &rfds); ! /* On Mac a zero timeout almost never works. At least wait one ! * millisecond. */ ! if (waittime == 0) ! waittime = 1; ! #endif ! FD_ZERO(&wfds); ! FD_SET(sd, &wfds); ! tv.tv_sec = waittime / 1000; ! tv.tv_usec = (waittime % 1000) * 1000; ! ! ch_logn(channel, "Waiting for connection (timeout %d msec)...\n", ! waittime); ! ret = select((int)sd + 1, #ifdef PASS_RFDS ! &rfds, #else ! NULL, #endif ! &wfds, NULL, &tv); ! if (ret < 0) ! { ! SOCK_ERRNO; ! ch_errorn(channel, "channel_open: Connect failed with errno %d\n", ! errno); ! PERROR(_(e_cannot_connect)); ! sock_close(sd); ! channel_free(channel); ! return NULL; ! } #ifdef PASS_RFDS ! if (ret == 0 && FD_ISSET(sd, &rfds) && FD_ISSET(sd, &wfds)) ! { ! /* For OS X, this implies error. See tcp(4). */ ! ch_error(channel, "channel_open: Connect failed\n"); ! EMSG(_(e_cannot_connect)); ! sock_close(sd); ! channel_free(channel); ! return NULL; ! } #endif ! if (!FD_ISSET(sd, &wfds)) ! { ! /* don't give an error, we just timed out. */ ! ch_error(channel, "Connection timed out\n"); ! sock_close(sd); ! channel_free(channel); ! return NULL; } - ch_log(channel, "Connection made\n"); } if (waittime >= 0) --- 531,715 ---- server.sin_port = htons(port); if ((host = gethostbyname(hostname)) == NULL) { ! ch_error(channel, "in gethostbyname() in channel_open()"); PERROR("E901: gethostbyname() in channel_open()"); channel_free(channel); return NULL; } memcpy((char *)&server.sin_addr, host->h_addr, host->h_length); ! #if defined(__APPLE__) && __APPLE__ == 1 ! /* On Mac a zero timeout almost never works. At least wait one ! * millisecond. */ ! if (waittime == 0) ! waittime = 1; #endif ! ! /* ! * For Unix we need to call connect() again after connect() failed. ! * On Win32 one time is sufficient. ! */ ! while (TRUE) ! { ! if (sd >= 0) sock_close(sd); + sd = socket(AF_INET, SOCK_STREAM, 0); + if (sd == -1) + { + ch_error(channel, "in socket() in channel_open()."); + PERROR("E898: socket() in channel_open()"); channel_free(channel); return NULL; } ! if (waittime >= 0) ! { ! /* Make connect() non-blocking. */ ! if ( ! #ifdef _WIN32 ! ioctlsocket(sd, FIONBIO, &val) < 0 ! #else ! fcntl(sd, F_SETFL, O_NONBLOCK) < 0 ! #endif ! ) ! { ! SOCK_ERRNO; ! ch_errorn(channel, ! "channel_open: Connect failed with errno %d", errno); ! sock_close(sd); ! channel_free(channel); ! return NULL; ! } ! } ! ! /* Try connecting to the server. */ ! ch_logsn(channel, "Connecting to %s port %d", hostname, port); ! ret = connect(sd, (struct sockaddr *)&server, sizeof(server)); ! ! SOCK_ERRNO; ! if (ret < 0) ! { ! if (errno != EWOULDBLOCK ! && errno != ECONNREFUSED ! #ifdef EINPROGRESS && errno != EINPROGRESS #endif ! ) ! { ! ch_errorn(channel, ! "channel_open: Connect failed with errno %d", errno); ! PERROR(_(e_cannot_connect)); ! sock_close(sd); ! channel_free(channel); ! return NULL; ! } } ! /* If we don't block and connect() failed then try using select() to ! * wait for the connection to be made. */ ! if (waittime >= 0 && ret < 0) ! { ! struct timeval tv; ! fd_set wfds; #if defined(__APPLE__) && __APPLE__ == 1 # define PASS_RFDS ! fd_set rfds; ! FD_ZERO(&rfds); ! FD_SET(sd, &rfds); ! #endif ! FD_ZERO(&wfds); ! FD_SET(sd, &wfds); ! ! tv.tv_sec = waittime / 1000; ! tv.tv_usec = (waittime % 1000) * 1000; ! #ifndef WIN32 ! gettimeofday(&start_tv, NULL); ! #endif ! ch_logn(channel, ! "Waiting for connection (waittime %d msec)...", waittime); ! ret = select((int)sd + 1, #ifdef PASS_RFDS ! &rfds, #else ! NULL, #endif ! &wfds, NULL, &tv); ! if (ret < 0) ! { ! SOCK_ERRNO; ! ch_errorn(channel, ! "channel_open: Connect failed with errno %d", errno); ! PERROR(_(e_cannot_connect)); ! sock_close(sd); ! channel_free(channel); ! return NULL; ! } #ifdef PASS_RFDS ! if (ret == 0 && FD_ISSET(sd, &rfds) && FD_ISSET(sd, &wfds)) ! { ! /* For OS X, this implies error. See tcp(4). */ ! ch_error(channel, "channel_open: Connect failed"); ! EMSG(_(e_cannot_connect)); ! sock_close(sd); ! channel_free(channel); ! return NULL; ! } #endif ! #ifdef WIN32 ! /* On Win32 select() is expected to work and wait for up to the ! * waittime for the socket to be open. */ ! if (!FD_ISSET(sd, &wfds) || ret == 0) ! #else ! /* See socket(7) for the behavior on Linux-like systems: ! * After putting the socket in non-blocking mode, connect() will ! * return EINPROGRESS, select() will not wait (as if writing is ! * possible), need to use getsockopt() to check if the socket is ! * actually open. */ ! getsockopt(sd, SOL_SOCKET, SO_ERROR, &so_error, &so_error_len); ! if (!FD_ISSET(sd, &wfds) || ret == 0 || so_error != 0) ! #endif ! { ! #ifndef WIN32 ! struct timeval end_tv; ! long elapsed_msec; ! ! gettimeofday(&end_tv, NULL); ! elapsed_msec = (end_tv.tv_sec - start_tv.tv_sec) * 1000 ! + (end_tv.tv_usec - start_tv.tv_usec) / 1000; ! if (waittime > 1 && elapsed_msec < waittime) ! { ! /* The port isn't ready but we also didn't get an error. ! * This happens when the server didn't open the socket ! * yet. Wait a bit and try again. */ ! mch_delay(waittime < 50 ? (long)waittime : 50L, TRUE); ! ui_breakcheck(); ! if (!got_int) ! { ! /* reduce the waittime by the elapsed time and the 50 ! * msec delay (or a bit more) */ ! waittime -= elapsed_msec; ! if (waittime > 50) ! waittime -= 50; ! else ! waittime = 1; ! continue; ! } ! /* we were interrupted, behave as if timed out */ ! } ! #endif ! /* We timed out. */ ! ch_error(channel, "Connection timed out"); ! sock_close(sd); ! channel_free(channel); ! return NULL; ! } ! ! ch_log(channel, "Connection made"); ! break; } } if (waittime >= 0) *************** *** 630,684 **** #endif } - /* Only retry for netbeans. TODO: can we use a waittime instead? */ - if (errno == ECONNREFUSED && close_cb != NULL) - { - sock_close(sd); - if ((sd = socket(AF_INET, SOCK_STREAM, 0)) == -1) - { - SOCK_ERRNO; - ch_log(channel, "socket() retry in channel_open()\n"); - PERROR("E900: socket() retry in channel_open()"); - channel_free(channel); - return NULL; - } - if (connect(sd, (struct sockaddr *)&server, sizeof(server))) - { - int retries = 36; - int success = FALSE; - - SOCK_ERRNO; - while (retries-- && ((errno == ECONNREFUSED) - || (errno == EINTR))) - { - ch_log(channel, "retrying...\n"); - mch_delay(3000L, TRUE); - ui_breakcheck(); - if (got_int) - { - errno = EINTR; - break; - } - if (connect(sd, (struct sockaddr *)&server, - sizeof(server)) == 0) - { - success = TRUE; - break; - } - SOCK_ERRNO; - } - if (!success) - { - /* Get here when the server can't be found. */ - ch_error(channel, "Cannot connect to port after retry\n"); - PERROR(_("E899: Cannot connect to port after retry")); - sock_close(sd); - channel_free(channel); - return NULL; - } - } - } - channel->CH_SOCK = (sock_T)sd; channel->ch_close_cb = close_cb; --- 722,727 ---- *************** *** 1155,1161 **** if (typetv->v_type != VAR_NUMBER) { ch_error(channel, ! "Dropping message with invalid sequence number type\n"); free_tv(listtv); return FALSE; } --- 1198,1204 ---- if (typetv->v_type != VAR_NUMBER) { ch_error(channel, ! "Dropping message with invalid sequence number type"); free_tv(listtv); return FALSE; } *************** *** 1223,1229 **** { if (item->cq_seq_nr == seq_nr) { ! ch_log(channel, "Invoking one-time callback\n"); /* Remove the item from the list first, if the callback * invokes ch_close() the list will be cleared. */ remove_cb_node(head, item); --- 1266,1272 ---- { if (item->cq_seq_nr == seq_nr) { ! ch_log(channel, "Invoking one-time callback"); /* Remove the item from the list first, if the callback * invokes ch_close() the list will be cleared. */ remove_cb_node(head, item); *************** *** 1236,1251 **** item = item->cq_next; } if (!done) ! ch_log(channel, "Dropping message without callback\n"); } else if (channel->ch_callback != NULL) { /* invoke the channel callback */ ! ch_log(channel, "Invoking channel callback\n"); invoke_callback(channel, channel->ch_callback, argv); } else ! ch_log(channel, "Dropping message\n"); if (listtv != NULL) free_tv(listtv); --- 1279,1294 ---- item = item->cq_next; } if (!done) ! ch_log(channel, "Dropping message without callback"); } else if (channel->ch_callback != NULL) { /* invoke the channel callback */ ! ch_log(channel, "Invoking channel callback"); invoke_callback(channel, channel->ch_callback, argv); } else ! ch_log(channel, "Dropping message"); if (listtv != NULL) free_tv(listtv); *************** *** 1304,1310 **** void channel_close(channel_T *channel) { ! ch_log(channel, "Closing channel\n"); #ifdef FEAT_GUI channel_gui_unregister(channel); --- 1347,1353 ---- void channel_close(channel_T *channel) { ! ch_log(channel, "Closing channel"); #ifdef FEAT_GUI channel_gui_unregister(channel); *************** *** 1471,1477 **** int ret; if (timeout > 0) ! ch_logn(channel, "Waiting for up to %d msec\n", timeout); # ifdef WIN32 --- 1514,1520 ---- int ret; if (timeout > 0) ! ch_logn(channel, "Waiting for up to %d msec", timeout); # ifdef WIN32 *************** *** 1511,1517 **** # endif if (ret <= 0) { ! ch_log(channel, "Nothing to read\n"); return FAIL; } break; --- 1554,1560 ---- # endif if (ret <= 0) { ! ch_log(channel, "Nothing to read"); return FAIL; } break; *************** *** 1521,1532 **** struct pollfd fds; if (timeout > 0) ! ch_logn(channel, "Waiting for %d msec\n", timeout); fds.fd = fd; fds.events = POLLIN; if (poll(&fds, 1, timeout) <= 0) { ! ch_log(channel, "Nothing to read\n"); return FAIL; } # endif --- 1564,1575 ---- struct pollfd fds; if (timeout > 0) ! ch_logn(channel, "Waiting for %d msec", timeout); fds.fd = fd; fds.events = POLLIN; if (poll(&fds, 1, timeout) <= 0) { ! ch_log(channel, "Nothing to read"); return FAIL; } # endif *************** *** 1558,1564 **** if (channel->CH_OUT != CHAN_FD_INVALID) return channel->CH_OUT; #endif ! ch_error(channel, "channel_read() called while socket is closed\n"); return CHAN_FD_INVALID; } --- 1601,1607 ---- if (channel->CH_OUT != CHAN_FD_INVALID) return channel->CH_OUT; #endif ! ch_error(channel, "channel_read() called while socket is closed"); return CHAN_FD_INVALID; } *************** *** 1637,1643 **** * -> gui event loop or select loop * -> channel_read() */ ! ch_errors(channel, "%s(): Cannot read\n", func); channel_save(channel, (char_u *)DETACH_MSG, (int)STRLEN(DETACH_MSG)); /* TODO: When reading from stdout is not possible, should we try to --- 1680,1686 ---- * -> gui event loop or select loop * -> channel_read() */ ! ch_errors(channel, "%s(): Cannot read", func); channel_save(channel, (char_u *)DETACH_MSG, (int)STRLEN(DETACH_MSG)); /* TODO: When reading from stdout is not possible, should we try to *************** *** 1649,1655 **** if (len < 0) { ! ch_error(channel, "channel_read(): cannot read from channel\n"); PERROR(_("E896: read from channel")); } } --- 1692,1698 ---- if (len < 0) { ! ch_error(channel, "channel_read(): cannot read from channel"); PERROR(_("E896: read from channel")); } } *************** *** 1677,1683 **** sock_T fd = get_read_fd(channel); char_u *nl; ! ch_logsn(channel, "Blocking %s read, timeout: %d msec\n", mode == MODE_RAW ? "RAW" : "NL", channel->ch_timeout); while (TRUE) --- 1720,1726 ---- sock_T fd = get_read_fd(channel); char_u *nl; ! ch_logsn(channel, "Blocking %s read, timeout: %d msec", mode == MODE_RAW ? "RAW" : "NL", channel->ch_timeout); while (TRUE) *************** *** 1718,1724 **** } } if (log_fd != NULL) ! ch_logn(channel, "Returning %d bytes\n", (int)STRLEN(msg)); return msg; } --- 1761,1767 ---- } } if (log_fd != NULL) ! ch_logn(channel, "Returning %d bytes", (int)STRLEN(msg)); return msg; } *************** *** 1733,1739 **** int more; sock_T fd; ! ch_log(channel, "Reading JSON\n"); channel->ch_block_id = id; for (;;) { --- 1776,1782 ---- int more; sock_T fd; ! ch_log(channel, "Reading JSON"); channel->ch_block_id = id; for (;;) { *************** *** 1821,1827 **** { if (!channel->ch_error && fun != NULL) { ! ch_errors(channel, "%s(): write while not connected\n", fun); EMSG2("E630: %s(): write while not connected", fun); } channel->ch_error = TRUE; --- 1864,1870 ---- { if (!channel->ch_error && fun != NULL) { ! ch_errors(channel, "%s(): write while not connected", fun); EMSG2("E630: %s(): write while not connected", fun); } channel->ch_error = TRUE; *************** *** 1845,1851 **** { if (!channel->ch_error && fun != NULL) { ! ch_errors(channel, "%s(): write failed\n", fun); EMSG2("E631: %s(): write failed", fun); } channel->ch_error = TRUE; --- 1888,1894 ---- { if (!channel->ch_error && fun != NULL) { ! ch_errors(channel, "%s(): write failed", fun); EMSG2("E631: %s(): write failed", fun); } channel->ch_error = TRUE; *** ../vim-7.4.1350/src/eval.c 2016-02-18 20:18:04.974654638 +0100 --- src/eval.c 2016-02-18 22:03:30.838031691 +0100 *************** *** 504,509 **** --- 504,510 ---- #endif #ifdef FEAT_CHANNEL static void f_ch_close(typval_T *argvars, typval_T *rettv); + static void f_ch_log(typval_T *argvars, typval_T *rettv); static void f_ch_logfile(typval_T *argvars, typval_T *rettv); static void f_ch_open(typval_T *argvars, typval_T *rettv); static void f_ch_readraw(typval_T *argvars, typval_T *rettv); *************** *** 8124,8129 **** --- 8125,8131 ---- #endif #ifdef FEAT_CHANNEL {"ch_close", 1, 1, f_ch_close}, + {"ch_log", 1, 2, f_ch_log}, {"ch_logfile", 1, 2, f_ch_logfile}, {"ch_open", 1, 2, f_ch_open}, {"ch_readraw", 1, 2, f_ch_readraw}, *************** *** 9950,9955 **** --- 9952,9972 ---- } /* + * "ch_log()" function + */ + static void + f_ch_log(typval_T *argvars, typval_T *rettv UNUSED) + { + char_u *msg = get_tv_string(&argvars[0]); + channel_T *channel = NULL; + + if (argvars[1].v_type != VAR_UNKNOWN) + channel = get_channel_arg(&argvars[1]); + + ch_log(channel, (char *)msg); + } + + /* * "ch_logfile()" function */ static void *************** *** 14603,14611 **** --- 14620,14649 ---- cmd = ga.ga_data; #endif } + #ifdef USE_ARGV + # ifdef FEAT_CHANNEL + if (ch_log_active()) + { + garray_T ga; + int i; + + ga_init2(&ga, (int)sizeof(char), 200); + for (i = 0; i < argc; ++i) + { + if (i > 0) + ga_concat(&ga, (char_u *)" "); + ga_concat(&ga, (char_u *)argv[i]); + } + ch_logs(NULL, "Starting job: %s", ga.ga_data); + ga_clear(&ga); + } + # endif mch_start_job(argv, job, &options); #else + # ifdef FEAT_CHANNEL + ch_logs(NULL, "Starting job: %s", cmd); + # endif mch_start_job((char *)cmd, job, &options); #endif *** ../vim-7.4.1350/src/netbeans.c 2016-02-13 23:22:35.093363549 +0100 --- src/netbeans.c 2016-02-18 21:41:43.583567462 +0100 *************** *** 213,219 **** if (hostname != NULL && address != NULL && password != NULL) { port = atoi(address); ! nb_channel = channel_open(hostname, port, 0, nb_channel_closed); if (nb_channel != NULL) { /* success */ --- 213,219 ---- if (hostname != NULL && address != NULL && password != NULL) { port = atoi(address); ! nb_channel = channel_open(hostname, port, 3000, nb_channel_closed); if (nb_channel != NULL) { /* success */ *** ../vim-7.4.1350/src/proto/channel.pro 2016-02-16 21:02:17.603873545 +0100 --- src/proto/channel.pro 2016-02-18 21:51:40.593424945 +0100 *************** *** 1,5 **** --- 1,8 ---- /* channel.c */ void ch_logfile(FILE *file); + int ch_log_active(void); + void ch_log(channel_T *ch, char *msg); + void ch_logs(channel_T *ch, char *msg, char *name); channel_T *add_channel(void); void channel_free(channel_T *channel); void channel_gui_register(channel_T *channel); *** ../vim-7.4.1350/src/testdir/test_channel.vim 2016-02-16 22:01:23.822490218 +0100 --- src/testdir/test_channel.vim 2016-02-18 22:05:24.856845698 +0100 *************** *** 31,47 **** let s:chopt = {} " Run "testfunc" after sarting the server and stop the server afterwards. ! func s:run_server(testfunc) " The Python program writes the port number in Xportnr. call delete("Xportnr") try if has('job') ! let s:job = job_start(s:python . " test_channel.py") elseif has('win32') ! exe 'silent !start cmd /c start "test_channel" ' . s:python . ' test_channel.py' else ! exe 'silent !' . s:python . ' test_channel.py&' endif " Wait for up to 2 seconds for the port number to be there. --- 31,54 ---- let s:chopt = {} " Run "testfunc" after sarting the server and stop the server afterwards. ! func s:run_server(testfunc, ...) " The Python program writes the port number in Xportnr. call delete("Xportnr") + if a:0 == 1 + let arg = ' ' . a:1 + else + let arg = '' + endif + let cmd = s:python . " test_channel.py" . arg + try if has('job') ! let s:job = job_start(cmd) elseif has('win32') ! exe 'silent !start cmd /c start "test_channel" ' . cmd else ! exe 'silent !' . cmd . '&' endif " Wait for up to 2 seconds for the port number to be there. *************** *** 175,180 **** --- 182,188 ---- endfunc func Test_communicate() + call ch_log('Test_communicate()') call s:run_server('s:communicate') endfunc *************** *** 203,208 **** --- 211,217 ---- endfunc func Test_two_channels() + call ch_log('Test_two_channels()') call s:run_server('s:two_channels') endfunc *************** *** 220,225 **** --- 229,235 ---- endfunc func Test_server_crash() + call ch_log('Test_server_crash()') call s:run_server('s:server_crash') endfunc *************** *** 248,253 **** --- 258,264 ---- endfunc func Test_channel_handler() + call ch_log('Test_channel_handler()') let s:chopt.callback = 's:Handler' call s:run_server('s:channel_handler') let s:chopt.callback = function('s:Handler') *************** *** 261,269 **** " TODO: Make this work again for MS-Windows. return endif let start = reltime() let handle = ch_open('localhost:9876', s:chopt) ! if ch_status(handle) == "fail" " Oops, port does exists. call ch_close(handle) else --- 272,281 ---- " TODO: Make this work again for MS-Windows. return endif + call ch_log('Test_connect_waittime()') let start = reltime() let handle = ch_open('localhost:9876', s:chopt) ! if ch_status(handle) != "fail" " Oops, port does exists. call ch_close(handle) else *************** *** 272,278 **** endif let start = reltime() ! let handle = ch_open('localhost:9867', {'waittime': 2000}) if ch_status(handle) != "fail" " Oops, port does exists. call ch_close(handle) --- 284,290 ---- endif let start = reltime() ! let handle = ch_open('localhost:9867', {'waittime': 500}) if ch_status(handle) != "fail" " Oops, port does exists. call ch_close(handle) *************** *** 280,286 **** " Failed connection doesn't wait the full time on Unix. " TODO: why is MS-Windows different? let elapsed = reltime(start) ! call assert_true(reltimefloat(elapsed) < (has('unix') ? 1.0 : 3.0)) endif endfunc --- 292,298 ---- " Failed connection doesn't wait the full time on Unix. " TODO: why is MS-Windows different? let elapsed = reltime(start) ! call assert_true(reltimefloat(elapsed) < 1.0) endif endfunc *************** *** 288,293 **** --- 300,306 ---- if !has('job') return endif + call ch_log('Test_raw_pipe()') let job = job_start(s:python . " test_channel_pipe.py", {'mode': 'raw'}) call assert_equal("run", job_status(job)) try *************** *** 311,316 **** --- 324,330 ---- if !has('job') return endif + call ch_log('Test_nl_pipe()') let job = job_start(s:python . " test_channel_pipe.py") call assert_equal("run", job_status(job)) try *************** *** 346,351 **** --- 360,366 ---- endfunc func Test_unlet_handle() + call ch_log('Test_unlet_handle()') call s:run_server('s:unlet_handle') endfunc *************** *** 366,378 **** --- 381,416 ---- endfunc func Test_close_handle() + call ch_log('Test_close_handle()') call s:run_server('s:close_handle') endfunc """""""""" func Test_open_fail() + call ch_log('Test_open_fail()') silent! let ch = ch_open("noserver") echo ch let d = ch endfunc + + """""""""" + + func s:open_delay(port) + " Wait up to a second for the port to open. + let s:chopt.waittime = 1000 + let channel = ch_open('localhost:' . a:port, s:chopt) + unlet s:chopt.waittime + if ch_status(channel) == "fail" + call assert_false(1, "Can't open channel") + return + endif + call assert_equal('got it', ch_sendexpr(channel, 'hello!')) + call ch_close(channel) + endfunc + + func Test_open_delay() + call ch_log('Test_open_delay()') + " The server will wait half a second before creating the port. + call s:run_server('s:open_delay', 'delay') + endfunc *** ../vim-7.4.1350/src/testdir/test_channel.py 2016-02-13 23:28:17.637753771 +0100 --- src/testdir/test_channel.py 2016-02-17 22:54:02.749262439 +0100 *************** *** 9,14 **** --- 9,15 ---- import json import socket import sys + import time import threading try: *************** *** 158,166 **** --- 159,183 ---- class ThreadedTCPServer(socketserver.ThreadingMixIn, socketserver.TCPServer): pass + def writePortInFile(port): + # Write the port number in Xportnr, so that the test knows it. + f = open("Xportnr", "w") + f.write("{}".format(port)) + f.close() + if __name__ == "__main__": HOST, PORT = "localhost", 0 + # Wait half a second before opening the port to test waittime in ch_open(). + # We do want to get the port number, get that first. We cannot open the + # socket, guess a port is free. + if len(sys.argv) >= 2 and sys.argv[1] == 'delay': + PORT = 13684 + writePortInFile(PORT) + + print("Wait for it...") + time.sleep(0.5) + server = ThreadedTCPServer((HOST, PORT), ThreadedTCPRequestHandler) ip, port = server.server_address *************** *** 169,178 **** server_thread = threading.Thread(target=server.serve_forever) server_thread.start() ! # Write the port number in Xportnr, so that the test knows it. ! f = open("Xportnr", "w") ! f.write("{}".format(port)) ! f.close() print("Listening on port {}".format(port)) --- 186,192 ---- server_thread = threading.Thread(target=server.serve_forever) server_thread.start() ! writePortInFile(port) print("Listening on port {}".format(port)) *** ../vim-7.4.1350/src/version.c 2016-02-18 22:17:36.105244535 +0100 --- src/version.c 2016-02-18 22:20:29.131447154 +0100 *************** *** 749,750 **** --- 749,752 ---- { /* Add new patch number below this line */ + /**/ + 1351, /**/ -- "Never be afraid to tell the world who you are." -- Anonymous /// Bram Moolenaar -- Bram@Moolenaar.net -- http://www.Moolenaar.net \\\ /// sponsor Vim, vote for features -- http://www.Vim.org/sponsor/ \\\ \\\ an exciting new programming language -- http://www.Zimbu.org /// \\\ help me help AIDS victims -- http://ICCF-Holland.org ///