diff options
author | olgeni <olgeni@FreeBSD.org> | 2015-04-12 18:11:35 +0800 |
---|---|---|
committer | olgeni <olgeni@FreeBSD.org> | 2015-04-12 18:11:35 +0800 |
commit | d62df72a236fb60b73405d3afef942d8511d0e62 (patch) | |
tree | 0c8287c34a67ee8b0f28219d0587bdf832a74968 /lang/erlang/files | |
parent | 34581be98828c271d0af4283c75950a33f04b434 (diff) | |
download | freebsd-ports-graphics-d62df72a236fb60b73405d3afef942d8511d0e62.tar.gz freebsd-ports-graphics-d62df72a236fb60b73405d3afef942d8511d0e62.tar.zst freebsd-ports-graphics-d62df72a236fb60b73405d3afef942d8511d0e62.zip |
Upgrade to version 17.5.1.
Diffstat (limited to 'lang/erlang/files')
-rw-r--r-- | lang/erlang/files/patch-otp-17.4.1 | 1358 | ||||
-rw-r--r-- | lang/erlang/files/patch-otp-17.5.1 | 826 |
2 files changed, 826 insertions, 1358 deletions
diff --git a/lang/erlang/files/patch-otp-17.4.1 b/lang/erlang/files/patch-otp-17.4.1 deleted file mode 100644 index a6e71eefcdb..00000000000 --- a/lang/erlang/files/patch-otp-17.4.1 +++ /dev/null @@ -1,1358 +0,0 @@ -diff --git OTP_VERSION OTP_VERSION -index 5f9cbaa..ae704d6 100644 ---- OTP_VERSION -+++ OTP_VERSION -@@ -1 +1 @@ --17.4 -+17.4.1 -diff --git erts/doc/src/notes.xml erts/doc/src/notes.xml -index c896ee0..af0d4d7 100644 ---- erts/doc/src/notes.xml -+++ erts/doc/src/notes.xml -@@ -30,6 +30,65 @@ - </header> - <p>This document describes the changes made to the ERTS application.</p> - -+<section><title>Erts 6.3.1</title> -+ -+ <section><title>Fixed Bugs and Malfunctions</title> -+ <list> -+ <item> -+ <p> -+ Fix getifaddrs realloc pointer error</p> -+ <p> -+ When a buffer was exhausted and subsequently reallocated, -+ we could get an unsafe pointer pointing to faulty memory.</p> -+ <p> -+ For this to occur we would need to have a large number of -+ interfaces and a reallocation of memory to a lower -+ addresses.</p> -+ <p> -+ The symptom would be garbage returned from -+ erlang:port_control(Port, 25, []) -+ (prim_inet:getifaddrs(Port) resulting in a badarg) or a -+ segmentation fault.</p> -+ <p> -+ Own Id: OTP-12445</p> -+ </item> -+ <item> -+ <p> -+ Don't close all file descriptors twice in child_setup</p> -+ <p> -+ The commit c2b4eab25c907f453a394d382c04cd04e6c06b49 -+ introduced an error in which child_setup erroneously -+ tried to close all file descriptors twice.</p> -+ <p> -+ Use closefrom() if available when closing all file -+ descriptors.</p> -+ <p> -+ The function closefrom() was only used in the vfork() -+ case before but is now also used in the fork() case if -+ available.</p> -+ <p> -+ Own Id: OTP-12446</p> -+ </item> -+ <item> -+ <p> -+ During a crashdump all file descriptors are closed to -+ ensure the closing of the epmd port and to reserve a file -+ descriptor for the crashdump file.</p> -+ <p> -+ If a driver (third party library) cannot handle closing -+ of sockets this could result in a segmentation fault in -+ which case a crashdump would not be produced. This is now -+ fixed by only closing inets sockets via an emergency -+ close callback to the driver and thus closing the epmd -+ socket.</p> -+ <p> -+ Own Id: OTP-12447</p> -+ </item> -+ </list> -+ </section> -+ -+</section> -+ - <section><title>Erts 6.3</title> - - <section><title>Fixed Bugs and Malfunctions</title> -diff --git erts/emulator/beam/erl_driver.h erts/emulator/beam/erl_driver.h -index f9938fc..e498ac7 100644 ---- erts/emulator/beam/erl_driver.h -+++ erts/emulator/beam/erl_driver.h -@@ -133,7 +133,7 @@ typedef struct { - - #define ERL_DRV_EXTENDED_MARKER (0xfeeeeeed) - #define ERL_DRV_EXTENDED_MAJOR_VERSION 3 --#define ERL_DRV_EXTENDED_MINOR_VERSION 1 -+#define ERL_DRV_EXTENDED_MINOR_VERSION 2 - - /* - * The emulator will refuse to load a driver with a major version -@@ -361,6 +361,9 @@ typedef struct erl_drv_entry { - /* Called on behalf of driver_select when - it is safe to release 'event'. A typical - unix driver would call close(event) */ -+ void (*emergency_close)(ErlDrvData drv_data); -+ /* called when the port is closed abruptly. -+ specifically when erl_crash_dump is called. */ - /* When adding entries here, dont forget to pad in obsolete/driver.h */ - } ErlDrvEntry; - -diff --git erts/emulator/beam/global.h erts/emulator/beam/global.h -index 891046a..32a2dc4 100644 ---- erts/emulator/beam/global.h -+++ erts/emulator/beam/global.h -@@ -160,6 +160,7 @@ struct erts_driver_t_ { - void (*ready_async)(ErlDrvData drv_data, ErlDrvThreadData thread_data); /* Might be NULL */ - void (*process_exit)(ErlDrvData drv_data, ErlDrvMonitor *monitor); - void (*stop_select)(ErlDrvEvent event, void*); /* Might be NULL */ -+ void (*emergency_close)(ErlDrvData drv_data); /* Might be NULL */ - }; - - extern erts_driver_t *driver_list; -@@ -852,6 +853,7 @@ Uint erts_port_ioq_size(Port *pp); - void erts_stale_drv_select(Eterm, ErlDrvPort, ErlDrvEvent, int, int); - - Port *erts_get_heart_port(void); -+void erts_emergency_close_ports(void); - - #if defined(ERTS_SMP) && defined(ERTS_ENABLE_LOCK_COUNT) - void erts_lcnt_enable_io_lock_count(int enable); -diff --git erts/emulator/beam/io.c erts/emulator/beam/io.c -index 9ae973e..012a7d1 100644 ---- erts/emulator/beam/io.c -+++ erts/emulator/beam/io.c -@@ -7349,6 +7349,8 @@ no_stop_select_callback(ErlDrvEvent event, void* private) - erts_send_error_to_logger_nogl(dsbufp); - } - -+#define IS_DRIVER_VERSION_GE(DE,MAJOR,MINOR) \ -+ ((DE)->major_version >= (MAJOR) && (DE)->minor_version >= (MINOR)) - - static int - init_driver(erts_driver_t *drv, ErlDrvEntry *de, DE_Handle *handle) -@@ -7396,6 +7398,7 @@ init_driver(erts_driver_t *drv, ErlDrvEntry *de, DE_Handle *handle) - drv->timeout = de->timeout ? de->timeout : no_timeout_callback; - drv->ready_async = de->ready_async; - drv->process_exit = de->process_exit; -+ drv->emergency_close = IS_DRIVER_VERSION_GE(de,3,2) ? de->emergency_close : NULL; - if (de->stop_select) - drv->stop_select = de->stop_select; - else -@@ -7414,6 +7417,8 @@ init_driver(erts_driver_t *drv, ErlDrvEntry *de, DE_Handle *handle) - } - } - -+#undef IS_DRIVER_VERSION_GE -+ - void - erts_destroy_driver(erts_driver_t *drv) - { -@@ -7557,7 +7562,7 @@ Port *erts_get_heart_port(void) - if (!port) - continue; - /* only examine undead or alive ports */ -- if (erts_atomic32_read_nob(&port->state) & ERTS_PORT_SFLGS_DEAD) -+ if (erts_atomic32_read_nob(&port->state) & ERTS_PORT_SFLGS_INVALID_DRIVER_LOOKUP) - continue; - /* immediate atom compare */ - reg = port->common.u.alive.reg; -@@ -7568,3 +7573,23 @@ Port *erts_get_heart_port(void) - - return NULL; - } -+ -+void erts_emergency_close_ports(void) -+{ -+ int ix, max = erts_ptab_max(&erts_port); -+ -+ for (ix = 0; ix < max; ix++) { -+ Port *port = erts_pix2port(ix); -+ -+ if (!port) -+ continue; -+ /* only examine undead or alive ports */ -+ if (erts_atomic32_read_nob(&port->state) & ERTS_PORT_SFLGS_INVALID_DRIVER_LOOKUP) -+ continue; -+ -+ /* emergency close socket */ -+ if (port->drv_ptr->emergency_close) { -+ port->drv_ptr->emergency_close((ErlDrvData) port->drv_data); -+ } -+ } -+} -diff --git erts/emulator/drivers/common/inet_drv.c erts/emulator/drivers/common/inet_drv.c -index db8a251..04721d2 100644 ---- erts/emulator/drivers/common/inet_drv.c -+++ erts/emulator/drivers/common/inet_drv.c -@@ -268,14 +268,13 @@ static BOOL (WINAPI *fpSetHandleInformation)(HANDLE,DWORD,DWORD); - #define sock_htonl(x) htonl((x)) - #define sock_send(s,buf,len,flag) send((s),(buf),(len),(flag)) - #define sock_sendv(s, vec, size, np, flag) \ -- WSASend((s),(WSABUF*)(vec),\ -- (size),(np),(flag),NULL,NULL) -+ WSASend((s),(WSABUF*)(vec),(size),(np),(flag),NULL,NULL) - #define sock_recv(s,buf,len,flag) recv((s),(buf),(len),(flag)) - - #define sock_recvfrom(s,buf,blen,flag,addr,alen) \ -- recvfrom((s),(buf),(blen),(flag),(addr),(alen)) -+ recvfrom((s),(buf),(blen),(flag),(addr),(alen)) - #define sock_sendto(s,buf,blen,flag,addr,alen) \ -- sendto((s),(buf),(blen),(flag),(addr),(alen)) -+ sendto((s),(buf),(blen),(flag),(addr),(alen)) - #define sock_hostname(buf, len) gethostname((buf), (len)) - - #define sock_getservbyname(name,proto) getservbyname((name),(proto)) -@@ -360,9 +359,9 @@ static ssize_t writev_fallback(int fd, const struct iovec *iov, int iovcnt, int - #define sock_accept(s, addr, len) accept((s), (addr), (len)) - #define sock_send(s,buf,len,flag) inet_send((s),(buf),(len),(flag)) - #define sock_sendto(s,buf,blen,flag,addr,alen) \ -- sendto((s),(buf),(blen),(flag),(addr),(alen)) -+ sendto((s),(buf),(blen),(flag),(addr),(alen)) - #define sock_sendv(s, vec, size, np, flag) \ -- (*(np) = writev_fallback((s), (struct iovec*)(vec), (size), (*(np)))) -+ (*(np) = writev_fallback((s), (struct iovec*)(vec), (size), (*(np)))) - #define sock_sendmsg(s,msghdr,flag) sendmsg((s),(msghdr),(flag)) - - #define sock_open(af, type, proto) socket((af), (type), (proto)) -@@ -1178,6 +1177,7 @@ static ErlDrvSSizeT tcp_inet_ctl(ErlDrvData, unsigned int, - static void tcp_inet_timeout(ErlDrvData); - static void tcp_inet_process_exit(ErlDrvData, ErlDrvMonitor *); - static void inet_stop_select(ErlDrvEvent, void*); -+static void inet_emergency_close(ErlDrvData); - #ifdef __WIN32__ - static void tcp_inet_event(ErlDrvData, ErlDrvEvent); - static void find_dynamic_functions(void); -@@ -1288,7 +1288,8 @@ static struct erl_drv_entry tcp_inet_driver_entry = - ERL_DRV_FLAG_USE_PORT_LOCKING|ERL_DRV_FLAG_SOFT_BUSY, - NULL, - tcp_inet_process_exit, -- inet_stop_select -+ inet_stop_select, -+ inet_emergency_close - }; - - -@@ -1341,7 +1342,8 @@ static struct erl_drv_entry udp_inet_driver_entry = - ERL_DRV_FLAG_USE_PORT_LOCKING, - NULL, - NULL, -- inet_stop_select -+ inet_stop_select, -+ inet_emergency_close - }; - #endif - -@@ -1375,7 +1377,8 @@ static struct erl_drv_entry sctp_inet_driver_entry = - ERL_DRV_FLAG_USE_PORT_LOCKING, - NULL, - NULL, /* process_exit */ -- inet_stop_select -+ inet_stop_select, -+ inet_emergency_close - }; - #endif - -@@ -1421,7 +1424,7 @@ static int packet_inet_input(udp_descriptor* udesc, HANDLE event); - static int packet_inet_output(udp_descriptor* udesc, HANDLE event); - #endif - --/* convert descriptor poiner to inet_descriptor pointer */ -+/* convert descriptor pointer to inet_descriptor pointer */ - #define INETP(d) (&(d)->inet) - - #ifdef __OSE__ -@@ -4721,6 +4724,36 @@ static char* sockaddr_to_buf(struct sockaddr* addr, char* ptr, char* end) - return NULL; - } - -+/* sockaddr_bufsz_need -+ * Returns the number of bytes needed to store the information -+ * through sockaddr_to_buf -+ */ -+ -+static size_t sockaddr_bufsz_need(struct sockaddr* addr) -+{ -+ if (addr->sa_family == AF_INET || addr->sa_family == 0) { -+ return 1 + sizeof(struct in_addr); -+ } -+#if defined(HAVE_IN6) && defined(AF_INET6) -+ else if (addr->sa_family == AF_INET6) { -+ return 1 + sizeof(struct in6_addr); -+ } -+#endif -+#if defined(AF_LINK) -+ if (addr->sa_family == AF_LINK) { -+ struct sockaddr_dl *sdl_p = (struct sockaddr_dl*) addr; -+ return 2 + sdl_p->sdl_alen; -+ } -+#endif -+#if defined(AF_PACKET) && defined(HAVE_NETPACKET_PACKET_H) -+ else if(addr->sa_family == AF_PACKET) { -+ struct sockaddr_ll *sll_p = (struct sockaddr_ll*) addr; -+ return 2 + sll_p->sll_halen; -+ } -+#endif -+ return 0; -+} -+ - static char* buf_to_sockaddr(char* ptr, char* end, struct sockaddr* addr) - { - buf_check(ptr,end,1); -@@ -5799,6 +5832,11 @@ done: - } - - #elif defined(HAVE_GETIFADDRS) -+#ifdef DEBUG -+#define GETIFADDRS_BUFSZ (1) -+#else -+#define GETIFADDRS_BUFSZ (512) -+#endif - - static ErlDrvSSizeT inet_ctl_getifaddrs(inet_descriptor* desc_p, - char **rbuf_pp, ErlDrvSizeT rsize) -@@ -5809,15 +5847,15 @@ static ErlDrvSSizeT inet_ctl_getifaddrs(inet_descriptor* desc_p, - char *buf_p; - char *buf_alloc_p; - -- buf_size = 512; -- buf_alloc_p = ALLOC(buf_size); -+ buf_size = GETIFADDRS_BUFSZ; -+ buf_alloc_p = ALLOC(GETIFADDRS_BUFSZ); - buf_p = buf_alloc_p; - # define BUF_ENSURE(Size) \ - do { \ - int NEED_, GOT_ = buf_p - buf_alloc_p; \ - NEED_ = GOT_ + (Size); \ - if (NEED_ > buf_size) { \ -- buf_size = NEED_ + 512; \ -+ buf_size = NEED_ + GETIFADDRS_BUFSZ; \ - buf_alloc_p = REALLOC(buf_alloc_p, buf_size); \ - buf_p = buf_alloc_p + GOT_; \ - } \ -@@ -5830,7 +5868,7 @@ static ErlDrvSSizeT inet_ctl_getifaddrs(inet_descriptor* desc_p, - while (! (P_ = sockaddr_to_buf((sa), buf_p, \ - buf_alloc_p+buf_size))) { \ - int GOT_ = buf_p - buf_alloc_p; \ -- buf_size += 512; \ -+ buf_size += GETIFADDRS_BUFSZ; \ - buf_alloc_p = REALLOC(buf_alloc_p, buf_size); \ - buf_p = buf_alloc_p + GOT_; \ - } \ -@@ -5887,10 +5925,11 @@ static ErlDrvSSizeT inet_ctl_getifaddrs(inet_descriptor* desc_p, - || ifa_p->ifa_addr->sa_family == AF_PACKET - #endif - ) { -- char *bp = buf_p; -- BUF_ENSURE(1); -- SOCKADDR_TO_BUF(INET_IFOPT_HWADDR, ifa_p->ifa_addr); -- if (buf_p - bp < 4) buf_p = bp; /* Empty hwaddr */ -+ size_t need = sockaddr_bufsz_need(ifa_p->ifa_addr); -+ if (need > 3) { -+ BUF_ENSURE(1 + need); -+ SOCKADDR_TO_BUF(INET_IFOPT_HWADDR, ifa_p->ifa_addr); -+ } - } - #endif - } -@@ -5905,6 +5944,7 @@ static ErlDrvSSizeT inet_ctl_getifaddrs(inet_descriptor* desc_p, - return buf_size; - # undef BUF_ENSURE - } -+#undef GETIFADDRS_BUFSZ - - #else - -@@ -8204,6 +8244,19 @@ static void inet_stop(inet_descriptor* desc) - FREE(desc); - } - -+static void inet_emergency_close(ErlDrvData data) -+{ -+ /* valid for any (UDP, TCP or SCTP) descriptor */ -+ tcp_descriptor* tcp_desc = (tcp_descriptor*)data; -+ inet_descriptor* desc = INETP(tcp_desc); -+ DEBUGF(("inet_emergency_close(%ld) {s=%d\r\n", -+ (long)desc->port, desc->s)); -+ if (desc->s != INVALID_SOCKET) { -+ sock_close(desc->s); -+ } -+} -+ -+ - static void set_default_msgq_limits(ErlDrvPort port) - { - ErlDrvSizeT q_high = INET_HIGH_MSGQ_WATERMARK; -diff --git erts/emulator/sys/unix/erl_child_setup.c erts/emulator/sys/unix/erl_child_setup.c -index 94eb6b1..5ad92da 100644 ---- erts/emulator/sys/unix/erl_child_setup.c -+++ erts/emulator/sys/unix/erl_child_setup.c -@@ -101,7 +101,9 @@ main(int argc, char *argv[]) - if (sscanf(argv[CS_ARGV_FD_CR_IX], "%d:%d", &from, &to) != 2) - return 1; - --#if defined(__ANDROID__) -+#if defined(HAVE_CLOSEFROM) -+ closefrom(from); -+#elif defined(__ANDROID__) - for (i = from; i <= to; i++) { - if (i!=__system_properties_fd) - (void) close(i); -@@ -109,13 +111,6 @@ main(int argc, char *argv[]) - #else - for (i = from; i <= to; i++) - (void) close(i); --#endif /* __ANDROID__ */ -- --#if defined(HAVE_CLOSEFROM) -- closefrom(from); --#else -- for (i = from; i <= to; i++) -- (void) close(i); - #endif - - if (!(argv[CS_ARGV_WD_IX][0] == '.' && argv[CS_ARGV_WD_IX][1] == '\0') -@@ -147,8 +142,6 @@ main(int argc, char *argv[]) - return 1; - } - -- -- - #if defined(__ANDROID__) - int __system_properties_fd(void) - { -diff --git erts/emulator/sys/unix/sys.c erts/emulator/sys/unix/sys.c -index 0d677d5..cd87b32 100644 ---- erts/emulator/sys/unix/sys.c -+++ erts/emulator/sys/unix/sys.c -@@ -202,8 +202,6 @@ static erts_smp_atomic_t sys_misc_mem_sz; - #if defined(ERTS_SMP) - static void smp_sig_notify(char c); - static int sig_notify_fds[2] = {-1, -1}; --#elif defined(USE_THREADS) --static int async_fd[2]; - #endif - - #if CHLDWTHR || defined(ERTS_SMP) -@@ -246,6 +244,8 @@ static void note_child_death(int, int); - static void* child_waiter(void *); - #endif - -+static int crashdump_companion_cube_fd = -1; -+ - /********************* General functions ****************************/ - - /* This is used by both the drivers and general I/O, must be set early */ -@@ -575,6 +575,14 @@ erts_sys_pre_init(void) - close(fd); - } - -+ /* We need a file descriptor to close in the crashdump creation. -+ * We close this one to be sure we can get a fd for our real file ... -+ * so, we create one here ... a stone to carry all the way home. -+ */ -+ -+ crashdump_companion_cube_fd = open("/dev/null", O_RDONLY); -+ -+ /* don't lose it, there will be cake */ - } - - void -@@ -719,14 +727,13 @@ static ERTS_INLINE int - prepare_crash_dump(int secs) - { - #define NUFBUF (3) -- int i, max; -+ int i; - char env[21]; /* enough to hold any 64-bit integer */ - size_t envsz; - DeclareTmpHeapNoproc(heap,NUFBUF); - Port *heart_port; - Eterm *hp = heap; - Eterm list = NIL; -- int heart_fd[2] = {-1,-1}; - int has_heart = 0; - - UseTmpHeapNoproc(NUFBUF); -@@ -749,43 +756,22 @@ prepare_crash_dump(int secs) - alarm((unsigned int)secs); - } - -+ /* close all viable sockets via emergency close callbacks. -+ * Specifically we want to close epmd sockets. -+ */ -+ -+ erts_emergency_close_ports(); -+ - if (heart_port) { -- /* hearts input fd -- * We "know" drv_data is the in_fd since the port is started with read|write -- */ -- heart_fd[0] = (int)heart_port->drv_data; -- heart_fd[1] = (int)driver_data[heart_fd[0]].ofd; -- has_heart = 1; -- -+ has_heart = 1; - list = CONS(hp, make_small(8), list); hp += 2; -- - /* send to heart port, CMD = 8, i.e. prepare crash dump =o */ - erts_port_output(NULL, ERTS_PORT_SIG_FLG_FORCE_IMM_CALL, heart_port, - heart_port->common.id, list, NULL); - } - -- /* Make sure we unregister at epmd (unknown fd) and get at least -- one free filedescriptor (for erl_crash.dump) */ -- -- max = max_files; -- if (max < 1024) -- max = 1024; -- for (i = 3; i < max; i++) { --#if defined(ERTS_SMP) -- /* We don't want to close the signal notification pipe... */ -- if (i == sig_notify_fds[0] || i == sig_notify_fds[1]) -- continue; --#elif defined(USE_THREADS) -- /* We don't want to close the async notification pipe... */ -- if (i == async_fd[0] || i == async_fd[1]) -- continue; --#endif -- /* We don't want to close our heart yet ... */ -- if (i == heart_fd[0] || i == heart_fd[1]) -- continue; -- -- close(i); -- } -+ /* Make sure we have a fd for our crashdump file. */ -+ close(crashdump_companion_cube_fd); - - envsz = sizeof(env); - i = erts_sys_getenv__("ERL_CRASH_DUMP_NICE", env, &envsz); -@@ -1574,9 +1560,13 @@ static ErlDrvData spawn_start(ErlDrvPort port_num, char* name, SysDriverOpts* op - goto child_error; - } - -+#if defined(HAVE_CLOSEFROM) -+ closefrom(opts->use_stdio ? 3 : 5); -+#else - for (i = opts->use_stdio ? 3 : 5; i < max_files; i++) - (void) close(i); -- -+#endif -+ - if (opts->wd && chdir(opts->wd) < 0) - goto child_error; - -diff --git erts/vsn.mk erts/vsn.mk -index d0dc8f7..e4b071b 100644 ---- erts/vsn.mk -+++ erts/vsn.mk -@@ -17,7 +17,7 @@ - # %CopyrightEnd% - # - --VSN = 6.3 -+VSN = 6.3.1 - - # Port number 4365 in 4.2 - # Port number 4366 in 4.3 -diff --git lib/inets/doc/src/httpd.xml lib/inets/doc/src/httpd.xml -index 4ca038c..20c8a6b 100644 ---- lib/inets/doc/src/httpd.xml -+++ lib/inets/doc/src/httpd.xml -@@ -4,7 +4,7 @@ - <erlref> - <header> - <copyright> -- <year>1997</year><year>2013</year> -+ <year>1997</year><year>2015</year> - <holder>Ericsson AB. All Rights Reserved.</holder> - </copyright> - <legalnotice> -@@ -249,7 +249,16 @@ - <p>Limits the size of the message header of HTTP request. - Defaults to 10240. </p> - </item> -- -+ -+ <marker id="prop_max_content_length"></marker> -+ <tag>{max_content_length, integer()}</tag> -+ <item> -+ <p>Maximum Content-Length in an incoming request, in bytes. Requests -+ with content larger than this are answered with Status 413. -+ Defaults to 100000000 (100 MB). -+ </p> -+ </item> -+ - <marker id="prop_max_uri"></marker> - <tag>{max_uri_size, integer()}</tag> - <item> -diff --git lib/inets/doc/src/notes.xml lib/inets/doc/src/notes.xml -index fb70344..7f73aa5 100644 ---- lib/inets/doc/src/notes.xml -+++ lib/inets/doc/src/notes.xml -@@ -32,7 +32,40 @@ - <file>notes.xml</file> - </header> - -- <section><title>Inets 5.10.4</title> -+ <section><title>Inets 5.10.5</title> -+ -+ <section><title>Fixed Bugs and Malfunctions</title> -+ <list> -+ <item> -+ <p> -+ mod_alias now handles https-URIs properly</p> -+ <p> -+ Consistent view of configuration parameter -+ keep_alive_timeout, should be presented in the -+ httpd:info/[1,2] function in the same unit as it is -+ inputted.</p> -+ <p> -+ Own Id: OTP-12436 Aux Id: seq12786 </p> -+ </item> -+ </list> -+ </section> -+ -+ -+ <section><title>Improvements and New Features</title> -+ <list> -+ <item> -+ <p> -+ Gracefully handle invalid content-lenght headers instead -+ of crashing in list_to_integer.</p> -+ <p> -+ Own Id: OTP-12429</p> -+ </item> -+ </list> -+ </section> -+ -+</section> -+ -+<section><title>Inets 5.10.4</title> - - <section><title>Fixed Bugs and Malfunctions</title> - <list> -diff --git lib/inets/src/http_lib/http_internal.hrl lib/inets/src/http_lib/http_internal.hrl -index 53b776c..5442574 100644 ---- lib/inets/src/http_lib/http_internal.hrl -+++ lib/inets/src/http_lib/http_internal.hrl -@@ -1,7 +1,7 @@ - %% - %% %CopyrightBegin% - %% --%% Copyright Ericsson AB 2002-2014. All Rights Reserved. -+%% Copyright Ericsson AB 2002-2015. All Rights Reserved. - %% - %% The contents of this file are subject to the Erlang Public License, - %% Version 1.1, (the "License"); you may not use this file except in -@@ -28,6 +28,7 @@ - -define(HTTP_MAX_URI_SIZE, nolimit). - -define(HTTP_MAX_VERSION_STRING, 8). - -define(HTTP_MAX_METHOD_STRING, 20). -+-define(HTTP_MAX_CONTENT_LENGTH, 100000000). - - -ifndef(HTTP_DEFAULT_SSL_KIND). - -define(HTTP_DEFAULT_SSL_KIND, essl). -diff --git lib/inets/src/http_lib/http_request.erl lib/inets/src/http_lib/http_request.erl -index f295453..a0833dd 100644 ---- lib/inets/src/http_lib/http_request.erl -+++ lib/inets/src/http_lib/http_request.erl -@@ -1,7 +1,7 @@ - %% - %% %CopyrightBegin% - %% --%% Copyright Ericsson AB 2005-2014. All Rights Reserved. -+%% Copyright Ericsson AB 2005-2015. All Rights Reserved. - %% - %% The contents of this file are subject to the Erlang Public License, - %% Version 1.1, (the "License"); you may not use this file except in -@@ -21,8 +21,16 @@ - - -include("http_internal.hrl"). - ---export([headers/2, http_headers/1, is_absolut_uri/1]). -+-export([headers/2, http_headers/1, is_absolut_uri/1, key_value/1]). - -+ -+key_value(KeyValueStr) -> -+ case lists:splitwith(fun($:) -> false; (_) -> true end, KeyValueStr) of -+ {Key, [$: | Value]} -> -+ {http_util:to_lower(string:strip(Key)), string:strip(Value)}; -+ {_, []} -> -+ undefined -+ end. - %%------------------------------------------------------------------------- - %% headers(HeaderList, #http_request_h{}) -> #http_request_h{} - %% HeaderList - ["HeaderField:Value"] -@@ -34,14 +42,12 @@ - %%------------------------------------------------------------------------- - headers([], Headers) -> - Headers; --headers([Header | Tail], Headers) -> -- case lists:splitwith(fun($:) -> false; (_) -> true end, Header) of -- {Key, [$: | Value]} -> -- headers(Tail, headers(http_util:to_lower(string:strip(Key)), -- string:strip(Value), Headers)); -- {_, []} -> -- headers(Tail, Headers) -- end. -+headers([{Key, Value} | Tail], Headers) -> -+ headers(Tail, headers(Key, Value, Headers)); -+headers([undefined], Headers) -> -+ Headers; -+headers(KeyValues, Headers) -> -+ headers([key_value(KeyValue) || KeyValue <- KeyValues], Headers). - - %%------------------------------------------------------------------------- - %% headers(#http_request_h{}) -> HeaderList -diff --git lib/inets/src/http_server/httpd_conf.erl lib/inets/src/http_server/httpd_conf.erl -index 27446ca..55698d5 100644 ---- lib/inets/src/http_server/httpd_conf.erl -+++ lib/inets/src/http_server/httpd_conf.erl -@@ -1,7 +1,7 @@ - %% - %% %CopyrightBegin% - %% --%% Copyright Ericsson AB 1997-2013. All Rights Reserved. -+%% Copyright Ericsson AB 1997-2015. All Rights Reserved. - %% - %% The contents of this file are subject to the Erlang Public License, - %% Version 1.1, (the "License"); you may not use this file except in -@@ -205,13 +205,13 @@ load("MaxURISize " ++ MaxHeaderSize, []) -> - " is an invalid number of MaxHeaderSize")} - end; - --load("MaxBodySize " ++ MaxBodySize, []) -> -- case make_integer(MaxBodySize) of -+load("MaxContentLength " ++ Max, []) -> -+ case make_integer(Max) of - {ok, Integer} -> -- {ok, [], {max_body_size,Integer}}; -+ {ok, [], {max_content_length, Integer}}; - {error, _} -> -- {error, ?NICE(clean(MaxBodySize) ++ -- " is an invalid number of MaxBodySize")} -+ {error, ?NICE(clean(Max) ++ -+ " is an invalid number of MaxContentLength")} - end; - - load("ServerName " ++ ServerName, []) -> -@@ -337,7 +337,7 @@ load("MaxKeepAliveRequest " ++ MaxRequests, []) -> - load("KeepAliveTimeout " ++ Timeout, []) -> - case make_integer(Timeout) of - {ok, Integer} -> -- {ok, [], {keep_alive_timeout, Integer*1000}}; -+ {ok, [], {keep_alive_timeout, Integer}}; - {error, _} -> - {error, ?NICE(clean(Timeout)++" is an invalid KeepAliveTimeout")} - end; -@@ -569,6 +569,12 @@ validate_config_params([{max_body_size, Value} | Rest]) - validate_config_params([{max_body_size, Value} | _]) -> - throw({max_body_size, Value}); - -+validate_config_params([{max_content_length, Value} | Rest]) -+ when is_integer(Value) andalso (Value > 0) -> -+ validate_config_params(Rest); -+validate_config_params([{max_content_length, Value} | _]) -> -+ throw({max_content_length, Value}); -+ - validate_config_params([{server_name, Value} | Rest]) - when is_list(Value) -> - validate_config_params(Rest); -@@ -635,7 +641,7 @@ validate_config_params([{max_keep_alive_request, Value} | Rest]) - when is_integer(Value) andalso (Value > 0) -> - validate_config_params(Rest); - validate_config_params([{max_keep_alive_request, Value} | _]) -> -- throw({max_header_size, Value}); -+ throw({max_keep_alive_request, Value}); - - validate_config_params([{keep_alive_timeout, Value} | Rest]) - when is_integer(Value) andalso (Value >= 0) -> -@@ -799,7 +805,7 @@ store({server_tokens, ServerTokens} = Entry, _ConfigList) -> - Server = server(ServerTokens), - {ok, [Entry, {server, Server}]}; - store({keep_alive_timeout, KeepAliveTimeout}, _ConfigList) -> -- {ok, {keep_alive_timeout, KeepAliveTimeout * 1000}}; -+ {ok, {keep_alive_timeout, KeepAliveTimeout}}; - store(ConfigListEntry, _ConfigList) -> - {ok, ConfigListEntry}. - -diff --git lib/inets/src/http_server/httpd_request.erl lib/inets/src/http_server/httpd_request.erl -index 712c735..6985065 100644 ---- lib/inets/src/http_server/httpd_request.erl -+++ lib/inets/src/http_server/httpd_request.erl -@@ -1,7 +1,7 @@ - %% - %% %CopyrightBegin% - %% --%% Copyright Ericsson AB 2005-2014. All Rights Reserved. -+%% Copyright Ericsson AB 2005-2015. All Rights Reserved. - %% - %% The contents of this file are subject to the Erlang Public License, - %% Version 1.1, (the "License"); you may not use this file except in -@@ -118,18 +118,17 @@ validate(Method, Uri, Version) -> - %% create it. - %% ---------------------------------------------------------------------- - update_mod_data(ModData, Method, RequestURI, HTTPVersion, Headers)-> -- ParsedHeaders = tagup_header(Headers), -- PersistentConn = get_persistens(HTTPVersion, ParsedHeaders, -+ PersistentConn = get_persistens(HTTPVersion, Headers, - ModData#mod.config_db), - {ok, ModData#mod{data = [], - method = Method, - absolute_uri = format_absolute_uri(RequestURI, -- ParsedHeaders), -+ Headers), - request_uri = format_request_uri(RequestURI), - http_version = HTTPVersion, - request_line = Method ++ " " ++ RequestURI ++ - " " ++ HTTPVersion, -- parsed_header = ParsedHeaders, -+ parsed_header = Headers, - connection = PersistentConn}}. - - %%%======================================================================== -@@ -146,14 +145,14 @@ parse_method(_, _, _, Max, _, _) -> - %% We do not know the version of the client as it comes after the - %% method send the lowest version in the response so that the client - %% will be able to handle it. -- {error, {too_long, Max, 413, "Method unreasonably long"}, lowest_version()}. -+ {error, {size_error, Max, 413, "Method unreasonably long"}, lowest_version()}. - - parse_uri(_, _, Current, MaxURI, _, _) - when (Current > MaxURI) andalso (MaxURI =/= nolimit) -> - %% We do not know the version of the client as it comes after the - %% uri send the lowest version in the response so that the client - %% will be able to handle it. -- {error, {too_long, MaxURI, 414, "URI unreasonably long"},lowest_version()}; -+ {error, {size_error, MaxURI, 414, "URI unreasonably long"},lowest_version()}; - parse_uri(<<>>, URI, Current, Max, MaxSizes, Result) -> - {?MODULE, parse_uri, [URI, Current, Max, MaxSizes, Result]}; - parse_uri(<<?SP, Rest/binary>>, URI, _, _, MaxSizes, Result) -> -@@ -179,12 +178,12 @@ parse_version(<<?CR>> = Data, Version, Current, Max, MaxSizes, Result) -> - parse_version(<<Octet, Rest/binary>>, Version, Current, Max, MaxSizes, Result) when Current =< Max -> - parse_version(Rest, [Octet | Version], Current + 1, Max, MaxSizes, Result); - parse_version(_, _, _, Max,_,_) -> -- {error, {too_long, Max, 413, "Version string unreasonably long"}, lowest_version()}. -+ {error, {size_error, Max, 413, "Version string unreasonably long"}, lowest_version()}. - - parse_headers(_, _, _, Current, Max, _, Result) - when Max =/= nolimit andalso Current > Max -> - HttpVersion = lists:nth(3, lists:reverse(Result)), -- {error, {too_long, Max, 413, "Headers unreasonably long"}, HttpVersion}; -+ {error, {size_error, Max, 413, "Headers unreasonably long"}, HttpVersion}; - - parse_headers(<<>>, Header, Headers, Current, Max, MaxSizes, Result) -> - {?MODULE, parse_headers, [<<>>, Header, Headers, Current, Max, -@@ -204,14 +203,22 @@ parse_headers(<<?CR,?LF,?CR,?LF,Body/binary>>, [], [], _, _, _, Result) -> - Result])), - {ok, NewResult}; - parse_headers(<<?CR,?LF,?CR,?LF,Body/binary>>, Header, Headers, _, _, -- _, Result) -> -- HTTPHeaders = [lists:reverse(Header) | Headers], -- RequestHeaderRcord = -- http_request:headers(HTTPHeaders, #http_request_h{}), -- NewResult = -- list_to_tuple(lists:reverse([Body, {RequestHeaderRcord, -- HTTPHeaders} | Result])), -- {ok, NewResult}; -+ MaxSizes, Result) -> -+ case http_request:key_value(lists:reverse(Header)) of -+ undefined -> %% Skip headers with missing : -+ {ok, list_to_tuple(lists:reverse([Body, {http_request:headers(Headers, #http_request_h{}), Headers} | Result]))}; -+ NewHeader -> -+ case check_header(NewHeader, MaxSizes) of -+ ok -> -+ {ok, list_to_tuple(lists:reverse([Body, {http_request:headers([NewHeader | Headers], -+ #http_request_h{}), -+ [NewHeader | Headers]} | Result]))}; -+ -+ {error, Reason} -> -+ HttpVersion = lists:nth(3, lists:reverse(Result)), -+ {error, Reason, HttpVersion} -+ end -+ end; - - parse_headers(<<?CR,?LF,?CR>> = Data, Header, Headers, Current, Max, - MaxSizes, Result) -> -@@ -243,8 +250,21 @@ parse_headers(<<?LF, Octet, Rest/binary>>, Header, Headers, Current, Max, - MaxSizes, Result); - parse_headers(<<?CR,?LF, Octet, Rest/binary>>, Header, Headers, _, Max, - MaxSizes, Result) -> -- parse_headers(Rest, [Octet], [lists:reverse(Header) | Headers], -- 0, Max, MaxSizes, Result); -+ case http_request:key_value(lists:reverse(Header)) of -+ undefined -> %% Skip headers with missing : -+ parse_headers(Rest, [Octet], Headers, -+ 0, Max, MaxSizes, Result); -+ NewHeader -> -+ case check_header(NewHeader, MaxSizes) of -+ ok -> -+ parse_headers(Rest, [Octet], [NewHeader | Headers], -+ 0, Max, MaxSizes, Result); -+ {error, Reason} -> -+ HttpVersion = lists:nth(3, lists:reverse(Result)), -+ {error, Reason, HttpVersion} -+ end -+ end; -+ - parse_headers(<<?CR>> = Data, Header, Headers, Current, Max, - MaxSizes, Result) -> - {?MODULE, parse_headers, [Data, Header, Headers, Current, Max, -@@ -388,29 +408,25 @@ get_persistens(HTTPVersion,ParsedHeader,ConfigDB)-> - false - end. - -- --%%---------------------------------------------------------------------- --%% tagup_header --%% --%% Parses the header of a HTTP request and returns a key,value tuple --%% list containing Name and Value of each header directive as of: --%% --%% Content-Type: multipart/mixed -> {"Content-Type", "multipart/mixed"} --%% --%% But in http/1.1 the field-names are case insencitive so now it must be --%% Content-Type: multipart/mixed -> {"content-type", "multipart/mixed"} --%% The standard furthermore says that leading and traling white space --%% is not a part of the fieldvalue and shall therefore be removed. --%%---------------------------------------------------------------------- --tagup_header([]) -> []; --tagup_header([Line|Rest]) -> [tag(Line, [])|tagup_header(Rest)]. -- --tag([], Tag) -> -- {http_util:to_lower(lists:reverse(Tag)), ""}; --tag([$:|Rest], Tag) -> -- {http_util:to_lower(lists:reverse(Tag)), string:strip(Rest)}; --tag([Chr|Rest], Tag) -> -- tag(Rest, [Chr|Tag]). -- - lowest_version()-> - "HTTP/0.9". -+ -+check_header({"content-length", Value}, Maxsizes) -> -+ Max = proplists:get_value(max_content_length, Maxsizes), -+ MaxLen = length(integer_to_list(Max)), -+ case length(Value) =< MaxLen of -+ true -> -+ try -+ _ = list_to_integer(Value), -+ ok -+ catch _:_ -> -+ {error, {size_error, Max, 411, "content-length not an integer"}} -+ end; -+ false -> -+ {error, {size_error, Max, 413, "content-length unreasonably long"}} -+ end; -+check_header(_, _) -> -+ ok. -+ -+ -+ -diff --git lib/inets/src/http_server/httpd_request_handler.erl lib/inets/src/http_server/httpd_request_handler.erl -index 9bea58c..f7a9fe5 100644 ---- lib/inets/src/http_server/httpd_request_handler.erl -+++ lib/inets/src/http_server/httpd_request_handler.erl -@@ -1,7 +1,7 @@ - %% - %% %CopyrightBegin% - %% --%% Copyright Ericsson AB 1997-2014. All Rights Reserved. -+%% Copyright Ericsson AB 1997-2015. All Rights Reserved. - %% - %% The contents of this file are subject to the Erlang Public License, - %% Version 1.1, (the "License"); you may not use this file except in -@@ -96,8 +96,9 @@ init([Manager, ConfigDB, AcceptTimeout]) -> - proc_lib:init_ack({ok, self()}), - - {SocketType, Socket} = await_socket_ownership_transfer(AcceptTimeout), -- -- KeepAliveTimeOut = httpd_util:lookup(ConfigDB, keep_alive_timeout, 150000), -+ -+ %%Timeout value is in seconds we want it in milliseconds -+ KeepAliveTimeOut = 1000 * httpd_util:lookup(ConfigDB, keep_alive_timeout, 150), - - case http_transport:negotiate(SocketType, Socket, ?HANDSHAKE_TIMEOUT) of - {error, _Error} -> -@@ -119,11 +120,15 @@ continue_init(Manager, ConfigDB, SocketType, Socket, TimeOut) -> - MaxHeaderSize = max_header_size(ConfigDB), - MaxURISize = max_uri_size(ConfigDB), - NrOfRequest = max_keep_alive_request(ConfigDB), -- -+ MaxContentLen = max_content_length(ConfigDB), -+ - {_, Status} = httpd_manager:new_connection(Manager), - - MFA = {httpd_request, parse, [[{max_uri, MaxURISize}, {max_header, MaxHeaderSize}, -- {max_version, ?HTTP_MAX_VERSION_STRING}, {max_method, ?HTTP_MAX_METHOD_STRING}]]}, -+ {max_version, ?HTTP_MAX_VERSION_STRING}, -+ {max_method, ?HTTP_MAX_METHOD_STRING}, -+ {max_content_length, MaxContentLen} -+ ]]}, - - State = #state{mod = Mod, - manager = Manager, -@@ -207,7 +212,7 @@ handle_info({Proto, Socket, Data}, - set_new_data_size(cancel_request_timeout(State), NewDataSize) - end, - handle_http_msg(Result, NewState); -- {error, {too_long, MaxSize, ErrCode, ErrStr}, Version} -> -+ {error, {size_error, MaxSize, ErrCode, ErrStr}, Version} -> - NewModData = ModData#mod{http_version = Version}, - httpd_response:send_status(NewModData, ErrCode, ErrStr), - Reason = io_lib:format("~p: ~p max size is ~p~n", -@@ -444,8 +449,7 @@ handle_body(#state{headers = Headers, body = Body, mod = ModData} = State, - error_log(Reason, ModData), - {stop, normal, State#state{response_sent = true}}; - _ -> -- Length = -- list_to_integer(Headers#http_request_h.'content-length'), -+ Length = list_to_integer(Headers#http_request_h.'content-length'), - case ((Length =< MaxBodySize) or (MaxBodySize == nolimit)) of - true -> - case httpd_request:whole_body(Body, Length) of -@@ -454,7 +458,7 @@ handle_body(#state{headers = Headers, body = Body, mod = ModData} = State, - ModData#mod.socket, - [{active, once}]), - {noreply, State#state{mfa = -- {Module, Function, Args}}}; -+ {Module, Function, Args}}}; - - {ok, NewBody} -> - handle_response( -@@ -471,7 +475,7 @@ handle_body(#state{headers = Headers, body = Body, mod = ModData} = State, - handle_expect(#state{headers = Headers, mod = - #mod{config_db = ConfigDB} = ModData} = State, - MaxBodySize) -> -- Length = Headers#http_request_h.'content-length', -+ Length = list_to_integer(Headers#http_request_h.'content-length'), - case expect(Headers, ModData#mod.http_version, ConfigDB) of - continue when (MaxBodySize > Length) orelse (MaxBodySize =:= nolimit) -> - httpd_response:send_status(ModData, 100, ""), -@@ -545,9 +549,13 @@ handle_next_request(#state{mod = #mod{connection = true} = ModData, - init_data = ModData#mod.init_data}, - MaxHeaderSize = max_header_size(ModData#mod.config_db), - MaxURISize = max_uri_size(ModData#mod.config_db), -+ MaxContentLen = max_content_length(ModData#mod.config_db), - - MFA = {httpd_request, parse, [[{max_uri, MaxURISize}, {max_header, MaxHeaderSize}, -- {max_version, ?HTTP_MAX_VERSION_STRING}, {max_method, ?HTTP_MAX_METHOD_STRING}]]}, -+ {max_version, ?HTTP_MAX_VERSION_STRING}, -+ {max_method, ?HTTP_MAX_METHOD_STRING}, -+ {max_content_length, MaxContentLen} -+ ]]}, - TmpState = State#state{mod = NewModData, - mfa = MFA, - max_keep_alive_request = decrease(Max), -@@ -630,3 +638,5 @@ max_body_size(ConfigDB) -> - max_keep_alive_request(ConfigDB) -> - httpd_util:lookup(ConfigDB, max_keep_alive_request, infinity). - -+max_content_length(ConfigDB) -> -+ httpd_util:lookup(ConfigDB, max_content_length, ?HTTP_MAX_CONTENT_LENGTH). -diff --git lib/inets/src/http_server/mod_alias.erl lib/inets/src/http_server/mod_alias.erl -index 0b9fe4c..5039cd5 100644 ---- lib/inets/src/http_server/mod_alias.erl -+++ lib/inets/src/http_server/mod_alias.erl -@@ -1,7 +1,7 @@ - %% - %% %CopyrightBegin% - %% --%% Copyright Ericsson AB 1997-2010. All Rights Reserved. -+%% Copyright Ericsson AB 1997-2015. All Rights Reserved. - %% - %% The contents of this file are subject to the Erlang Public License, - %% Version 1.1, (the "License"); you may not use this file except in -@@ -55,6 +55,7 @@ do(#mod{data = Data} = Info) -> - - do_alias(#mod{config_db = ConfigDB, - request_uri = ReqURI, -+ socket_type = SocketType, - data = Data}) -> - {ShortPath, Path, AfterPath} = - real_name(ConfigDB, ReqURI, which_alias(ConfigDB)), -@@ -70,8 +71,9 @@ do_alias(#mod{config_db = ConfigDB, - (LastChar =/= $/)) -> - ?hdrt("directory and last-char is a /", []), - ServerName = which_server_name(ConfigDB), -- Port = port_string( which_port(ConfigDB) ), -- URL = "http://" ++ ServerName ++ Port ++ ReqURI ++ "/", -+ Port = port_string(which_port(ConfigDB)), -+ Protocol = get_protocol(SocketType), -+ URL = Protocol ++ ServerName ++ Port ++ ReqURI ++ "/", - ReasonPhrase = httpd_util:reason_phrase(301), - Message = httpd_util:message(301, URL, ConfigDB), - {proceed, -@@ -94,6 +96,12 @@ port_string(80) -> - port_string(Port) -> - ":" ++ integer_to_list(Port). - -+get_protocol(ip_comm) -> -+ "http://"; -+get_protocol(_) -> -+ %% Should clean up to have only one ssl type essl vs ssl is not relevant any more -+ "https://". -+ - %% real_name - - real_name(ConfigDB, RequestURI, []) -> -diff --git lib/inets/test/http_format_SUITE.erl lib/inets/test/http_format_SUITE.erl -index d4a3f28..5952e9f 100644 ---- lib/inets/test/http_format_SUITE.erl -+++ lib/inets/test/http_format_SUITE.erl -@@ -1,7 +1,7 @@ - %% - %% %CopyrightBegin% - %% --%% Copyright Ericsson AB 2004-2014. All Rights Reserved. -+%% Copyright Ericsson AB 2004-2015. All Rights Reserved. - %% - %% The contents of this file are subject to the Erlang Public License, - %% Version 1.1, (the "License"); you may not use this file except in -@@ -355,10 +355,12 @@ http_request(Config) when is_list(Config) -> - "http://www.erlang.org", - "HTTP/1.1", - {#http_request_h{host = "www.erlang.org", te = []}, -- ["te: ","host:www.erlang.org"]}, <<>>} = -+ [{"te", []}, {"host", "www.erlang.org"}]}, <<>>} = - parse(httpd_request, parse, [[{max_header, ?HTTP_MAX_HEADER_SIZE}, - {max_version, ?HTTP_MAX_VERSION_STRING}, -- {max_method, ?HTTP_MAX_METHOD_STRING}]], -+ {max_method, ?HTTP_MAX_METHOD_STRING}, -+ {max_content_length, ?HTTP_MAX_CONTENT_LENGTH} -+ ]], - HttpHead), - - HttpHead1 = ["GET http://www.erlang.org HTTP/1.1" ++ -@@ -369,7 +371,9 @@ http_request(Config) when is_list(Config) -> - {#http_request_h{}, []}, <<>>} = - parse(httpd_request, parse, [[{max_header, ?HTTP_MAX_HEADER_SIZE}, - {max_version, ?HTTP_MAX_VERSION_STRING}, -- {max_method, ?HTTP_MAX_METHOD_STRING}]], HttpHead1), -+ {max_method, ?HTTP_MAX_METHOD_STRING}, -+ {max_content_length, ?HTTP_MAX_CONTENT_LENGTH} -+ ]], HttpHead1), - - - HttpHead2 = ["GET http://www.erlang.org HTTP/1.1" ++ -@@ -380,7 +384,9 @@ http_request(Config) when is_list(Config) -> - {#http_request_h{}, []}, <<>>} = - parse(httpd_request, parse, [[{max_header, ?HTTP_MAX_HEADER_SIZE}, - {max_version, ?HTTP_MAX_VERSION_STRING}, -- {max_method, ?HTTP_MAX_METHOD_STRING}]], HttpHead2), -+ {max_method, ?HTTP_MAX_METHOD_STRING}, -+ {max_content_length, ?HTTP_MAX_CONTENT_LENGTH} -+ ]], HttpHead2), - - %% Note the following body is not related to the headers above - HttpBody = ["<HTML>\n<HEAD>\n<TITLE> dummy </TITLE>\n</HEAD>\n<BODY>\n", -diff --git lib/inets/test/httpc_SUITE.erl lib/inets/test/httpc_SUITE.erl -index c535d59..390f2bb 100644 ---- lib/inets/test/httpc_SUITE.erl -+++ lib/inets/test/httpc_SUITE.erl -@@ -1,7 +1,7 @@ - %% - %% %CopyrightBegin% - %% --%% Copyright Ericsson AB 2004-2014. All Rights Reserved. -+%% Copyright Ericsson AB 2004-2015. All Rights Reserved. - %% - %% The contents of this file are subject to the Erlang Public License, - %% Version 1.1, (the "License"); you may not use this file except in -@@ -1246,8 +1246,9 @@ dummy_server_init(Caller, ip_comm, Inet, _) -> - dummy_ipcomm_server_loop({httpd_request, parse, [[{max_uri, ?HTTP_MAX_URI_SIZE}, - {max_header, ?HTTP_MAX_HEADER_SIZE}, - {max_version,?HTTP_MAX_VERSION_STRING}, -- {max_method, ?HTTP_MAX_METHOD_STRING}]]}, -- [], ListenSocket); -+ {max_method, ?HTTP_MAX_METHOD_STRING}, -+ {max_content_length, ?HTTP_MAX_CONTENT_LENGTH}]]}, -+ [], ListenSocket); - - dummy_server_init(Caller, ssl, Inet, SSLOptions) -> - BaseOpts = [binary, {reuseaddr,true}, {active, false} | -@@ -1261,7 +1262,9 @@ dummy_ssl_server_init(Caller, BaseOpts, Inet) -> - dummy_ssl_server_loop({httpd_request, parse, [[{max_uri, ?HTTP_MAX_URI_SIZE}, - {max_method, ?HTTP_MAX_METHOD_STRING}, - {max_version,?HTTP_MAX_VERSION_STRING}, -- {max_method, ?HTTP_MAX_METHOD_STRING}]]}, -+ {max_method, ?HTTP_MAX_METHOD_STRING}, -+ {max_content_length, ?HTTP_MAX_CONTENT_LENGTH} -+ ]]}, - [], ListenSocket). - - dummy_ipcomm_server_loop(MFA, Handlers, ListenSocket) -> -@@ -1338,16 +1341,20 @@ handle_request(Module, Function, Args, Socket) -> - stop -> - stop; - <<>> -> -- {httpd_request, parse, [[<<>>, [{max_uri, ?HTTP_MAX_URI_SIZE}, -+ {httpd_request, parse, [[{max_uri,?HTTP_MAX_URI_SIZE}, - {max_header, ?HTTP_MAX_HEADER_SIZE}, - {max_version,?HTTP_MAX_VERSION_STRING}, -- {max_method, ?HTTP_MAX_METHOD_STRING}]]]}; -+ {max_method, ?HTTP_MAX_METHOD_STRING}, -+ {max_content_length, ?HTTP_MAX_CONTENT_LENGTH} -+ ]]}; - Data -> - handle_request(httpd_request, parse, - [Data, [{max_uri, ?HTTP_MAX_URI_SIZE}, -- {max_header, ?HTTP_MAX_HEADER_SIZE}, -- {max_version,?HTTP_MAX_VERSION_STRING}, -- {max_method, ?HTTP_MAX_METHOD_STRING}]], Socket) -+ {max_header, ?HTTP_MAX_HEADER_SIZE}, -+ {max_version,?HTTP_MAX_VERSION_STRING}, -+ {max_method, ?HTTP_MAX_METHOD_STRING}, -+ {max_content_length, ?HTTP_MAX_CONTENT_LENGTH} -+ ]], Socket) - end; - NewMFA -> - NewMFA -@@ -1437,7 +1444,7 @@ dummy_ssl_server_hang_loop(_) -> - - ensure_host_header_with_port([]) -> - false; --ensure_host_header_with_port(["host: " ++ Host| _]) -> -+ensure_host_header_with_port([{"host", Host}| _]) -> - case string:tokens(Host, [$:]) of - [_ActualHost, _Port] -> - true; -@@ -1449,7 +1456,7 @@ ensure_host_header_with_port([_|T]) -> - - auth_header([]) -> - auth_header_not_found; --auth_header(["authorization:" ++ Value | _]) -> -+auth_header([{"authorization", Value} | _]) -> - {ok, string:strip(Value)}; - auth_header([_ | Tail]) -> - auth_header(Tail). -@@ -1466,7 +1473,7 @@ handle_auth("Basic " ++ UserInfo, Challange, DefaultResponse) -> - - check_cookie([]) -> - ct:fail(no_cookie_header); --check_cookie(["cookie:" ++ _Value | _]) -> -+check_cookie([{"cookie", _} | _]) -> - ok; - check_cookie([_Head | Tail]) -> - check_cookie(Tail). -diff --git lib/inets/test/httpd_SUITE.erl lib/inets/test/httpd_SUITE.erl -index 4010597..342004f 100644 ---- lib/inets/test/httpd_SUITE.erl -+++ lib/inets/test/httpd_SUITE.erl -@@ -1,7 +1,7 @@ - %% - %% %CopyrightBegin% - %% --%% Copyright Ericsson AB 2013-2014. All Rights Reserved. -+%% Copyright Ericsson AB 2013-2015. All Rights Reserved. - %% - %% The contents of this file are subject to the Erlang Public License, - %% Version 1.1, (the "License"); you may not use this file except in -@@ -132,6 +132,7 @@ http_get() -> - bad_hex, - missing_CR, - max_header, -+ max_content_length, - ipv6 - ]. - -@@ -979,13 +980,22 @@ max_header(Config) when is_list(Config) -> - Host = ?config(host, Config), - case Version of - "HTTP/0.9" -> -- {skip, no_implemented}; -+ {skip, not_implemented}; - _ -> - dos_hostname(?config(type, Config), ?config(port, Config), Host, - ?config(node, Config), Version, ?MAX_HEADER_SIZE) - end. - - %%------------------------------------------------------------------------- -+max_content_length() -> -+ ["Denial Of Service (DOS) attack, prevented by max_content_length"]. -+max_content_length(Config) when is_list(Config) -> -+ Version = ?config(http_version, Config), -+ Host = ?config(host, Config), -+ garbage_content_length(?config(type, Config), ?config(port, Config), Host, -+ ?config(node, Config), Version). -+ -+%%------------------------------------------------------------------------- - security_1_1(Config) when is_list(Config) -> - security([{http_version, "HTTP/1.1"} | Config]). - -@@ -1368,7 +1378,9 @@ server_config(http_reload, Config) -> - server_config(https_reload, Config) -> - [{keep_alive_timeout, 2}] ++ server_config(https, Config); - server_config(http_limit, Config) -> -- [{max_clients, 1}] ++ server_config(http, Config); -+ [{max_clients, 1}, -+ %% Make sure option checking code is run -+ {max_content_length, 100000002}] ++ server_config(http, Config); - server_config(https_limit, Config) -> - [{max_clients, 1}] ++ server_config(https, Config); - server_config(http_basic_auth, Config) -> -@@ -1814,7 +1826,7 @@ dos_hostname(Type, Port, Host, Node, Version, Max) -> - - ok = httpd_test_lib:verify_request(Type, Host, Port, Node, - dos_hostname_request(TooLongHeader, Version), -- [{statuscode, dos_code(Version)}, -+ [{statuscode, request_entity_too_large_code(Version)}, - {version, Version}]). - dos_hostname_request(Host, Version) -> - dos_http_request("GET / ", Version, Host). -@@ -1824,11 +1836,32 @@ dos_http_request(Request, "HTTP/1.1" = Version, Host) -> - dos_http_request(Request, Version, Host) -> - Request ++ Version ++ "\r\nhost:" ++ Host ++ "\r\n\r\n". - --dos_code("HTTP/1.0") -> -+request_entity_too_large_code("HTTP/1.0") -> - 403; %% 413 not defined in HTTP/1.0 --dos_code(_) -> -+request_entity_too_large_code(_) -> - 413. - -+length_required_code("HTTP/1.0") -> -+ 403; %% 411 not defined in HTTP/1.0 -+length_required_code(_) -> -+ 411. -+ -+garbage_content_length(Type, Port, Host, Node, Version) -> -+ ok = httpd_test_lib:verify_request(Type, Host, Port, Node, -+ garbage_content_length_request("GET / ", Version, Host, "aaaa"), -+ [{statuscode, length_required_code(Version)}, -+ {version, Version}]), -+ ok = httpd_test_lib:verify_request(Type, Host, Port, Node, -+ garbage_content_length_request("GET / ", Version, Host, -+ lists:duplicate($a, 100)), -+ [{statuscode, request_entity_too_large_code(Version)}, -+ {version, Version}]). -+ -+garbage_content_length_request(Request, Version, Host, Garbage) -> -+ http_request(Request, Version, Host, -+ {"content-length:" ++ Garbage, "Body with garbage content length indicator"}). -+ -+ - update_password(Node, ServerRoot, _Address, Port, AuthPrefix, Dir, Old, New)-> - Directory = filename:join([ServerRoot, "htdocs", AuthPrefix ++ Dir]), - rpc:call(Node, mod_auth, update_password, -diff --git lib/inets/vsn.mk lib/inets/vsn.mk -index dbae5e4..7d11916 100644 ---- lib/inets/vsn.mk -+++ lib/inets/vsn.mk -@@ -18,6 +18,6 @@ - # %CopyrightEnd% - - APPLICATION = inets --INETS_VSN = 5.10.4 -+INETS_VSN = 5.10.5 - PRE_VSN = - APP_VSN = "$(APPLICATION)-$(INETS_VSN)$(PRE_VSN)" -diff --git otp_versions.table otp_versions.table -index 5753385..41c05e7 100644 ---- otp_versions.table -+++ otp_versions.table -@@ -1,3 +1,4 @@ -+OTP-17.4.1 : erts-6.3.1 inets-5.10.5 # asn1-3.0.3 common_test-1.9 compiler-5.0.3 cosEvent-2.1.15 cosEventDomain-1.1.14 cosFileTransfer-1.1.16 cosNotification-1.1.21 cosProperty-1.1.17 cosTime-1.1.14 cosTransactions-1.2.14 crypto-3.4.2 debugger-4.0.2 dialyzer-2.7.3 diameter-1.8 edoc-0.7.16 eldap-1.1 erl_docgen-0.3.7 erl_interface-3.7.20 et-1.5 eunit-2.2.9 gs-1.5.16 hipe-3.11.2 ic-4.3.6 jinterface-1.5.12 kernel-3.1 megaco-3.17.3 mnesia-4.12.4 observer-2.0.3 odbc-2.10.22 orber-3.7.1 os_mon-2.3 ose-1.0.2 otp_mibs-1.0.10 parsetools-2.0.12 percept-0.8.10 public_key-0.22.1 reltool-0.6.6 runtime_tools-1.8.15 sasl-2.4.1 snmp-5.1.1 ssh-3.1 ssl-5.3.8 stdlib-2.3 syntax_tools-1.6.17 test_server-3.7.2 tools-2.7.1 typer-0.9.8 webtool-0.8.10 wx-1.3.2 xmerl-1.3.7 : - OTP-17.4 : asn1-3.0.3 common_test-1.9 compiler-5.0.3 crypto-3.4.2 debugger-4.0.2 dialyzer-2.7.3 diameter-1.8 edoc-0.7.16 eldap-1.1 erl_docgen-0.3.7 erl_interface-3.7.20 erts-6.3 eunit-2.2.9 hipe-3.11.2 inets-5.10.4 jinterface-1.5.12 kernel-3.1 megaco-3.17.3 mnesia-4.12.4 observer-2.0.3 odbc-2.10.22 otp_mibs-1.0.10 parsetools-2.0.12 percept-0.8.10 runtime_tools-1.8.15 snmp-5.1.1 ssh-3.1 ssl-5.3.8 stdlib-2.3 syntax_tools-1.6.17 test_server-3.7.2 tools-2.7.1 wx-1.3.2 # cosEvent-2.1.15 cosEventDomain-1.1.14 cosFileTransfer-1.1.16 cosNotification-1.1.21 cosProperty-1.1.17 cosTime-1.1.14 cosTransactions-1.2.14 et-1.5 gs-1.5.16 ic-4.3.6 orber-3.7.1 os_mon-2.3 ose-1.0.2 public_key-0.22.1 reltool-0.6.6 sasl-2.4.1 typer-0.9.8 webtool-0.8.10 xmerl-1.3.7 : - OTP-17.3.4 : erts-6.2.1 # asn1-3.0.2 common_test-1.8.2 compiler-5.0.2 cosEvent-2.1.15 cosEventDomain-1.1.14 cosFileTransfer-1.1.16 cosNotification-1.1.21 cosProperty-1.1.17 cosTime-1.1.14 cosTransactions-1.2.14 crypto-3.4.1 debugger-4.0.1 dialyzer-2.7.2 diameter-1.7.1 edoc-0.7.15 eldap-1.0.4 erl_docgen-0.3.6 erl_interface-3.7.19 et-1.5 eunit-2.2.8 gs-1.5.16 hipe-3.11.1 ic-4.3.6 inets-5.10.3 jinterface-1.5.11 kernel-3.0.3 megaco-3.17.2 mnesia-4.12.3 observer-2.0.2 odbc-2.10.21 orber-3.7.1 os_mon-2.3 ose-1.0.2 otp_mibs-1.0.9 parsetools-2.0.11 percept-0.8.9 public_key-0.22.1 reltool-0.6.6 runtime_tools-1.8.14 sasl-2.4.1 snmp-5.1 ssh-3.0.8 ssl-5.3.7 stdlib-2.2 syntax_tools-1.6.16 test_server-3.7.1 tools-2.7 typer-0.9.8 webtool-0.8.10 wx-1.3.1 xmerl-1.3.7 : - OTP-17.3.3 : ssh-3.0.8 # asn1-3.0.2 common_test-1.8.2 compiler-5.0.2 cosEvent-2.1.15 cosEventDomain-1.1.14 cosFileTransfer-1.1.16 cosNotification-1.1.21 cosProperty-1.1.17 cosTime-1.1.14 cosTransactions-1.2.14 crypto-3.4.1 debugger-4.0.1 dialyzer-2.7.2 diameter-1.7.1 edoc-0.7.15 eldap-1.0.4 erl_docgen-0.3.6 erl_interface-3.7.19 erts-6.2 et-1.5 eunit-2.2.8 gs-1.5.16 hipe-3.11.1 ic-4.3.6 inets-5.10.3 jinterface-1.5.11 kernel-3.0.3 megaco-3.17.2 mnesia-4.12.3 observer-2.0.2 odbc-2.10.21 orber-3.7.1 os_mon-2.3 ose-1.0.2 otp_mibs-1.0.9 parsetools-2.0.11 percept-0.8.9 public_key-0.22.1 reltool-0.6.6 runtime_tools-1.8.14 sasl-2.4.1 snmp-5.1 ssl-5.3.7 stdlib-2.2 syntax_tools-1.6.16 test_server-3.7.1 tools-2.7 typer-0.9.8 webtool-0.8.10 wx-1.3.1 xmerl-1.3.7 : diff --git a/lang/erlang/files/patch-otp-17.5.1 b/lang/erlang/files/patch-otp-17.5.1 new file mode 100644 index 00000000000..296b344a47c --- /dev/null +++ b/lang/erlang/files/patch-otp-17.5.1 @@ -0,0 +1,826 @@ +diff --git OTP_VERSION OTP_VERSION +index 6060b96..9cbaf23 100644 +--- OTP_VERSION ++++ OTP_VERSION +@@ -1 +1 @@ +-17.5 ++17.5.1 +diff --git lib/ssh/doc/src/notes.xml lib/ssh/doc/src/notes.xml +index f22bca3..acbf312 100644 +--- lib/ssh/doc/src/notes.xml ++++ lib/ssh/doc/src/notes.xml +@@ -29,6 +29,28 @@ + <file>notes.xml</file> + </header> + ++<section><title>Ssh 3.2.1</title> ++ ++ <section><title>Fixed Bugs and Malfunctions</title> ++ <list> ++ <item> ++ <p> ++ Ssh crashed if a message was sent on a channel with ++ packet_size = 0.</p> ++ <p> ++ A new option for ssh:daemon is also introduced: ++ <c>minimal_remote_max_packet_size</c>. This option sets ++ the least max packet size declaration that the daemon ++ will accept from a client. The default value is 0 to ++ maintain compatibility with OpenSSH and the rfc:s.</p> ++ <p> ++ Own Id: OTP-12645 Aux Id: seq12816 </p> ++ </item> ++ </list> ++ </section> ++ ++</section> ++ + <section><title>Ssh 3.2</title> + + <section><title>Fixed Bugs and Malfunctions</title> +diff --git lib/ssh/doc/src/ssh.xml lib/ssh/doc/src/ssh.xml +index d481a75..0e7e384 100644 +--- lib/ssh/doc/src/ssh.xml ++++ lib/ssh/doc/src/ssh.xml +@@ -338,6 +338,12 @@ + </warning> + </item> + ++ <tag><c><![CDATA[{minimal_remote_max_packet_size, non_negative_integer()}]]></c></tag> ++ <item> ++ <p>The least maximum packet size that the daemon will accept in channel open requests from the client. The default value is 0. ++ </p> ++ </item> ++ + <tag><c><![CDATA[{key_cb, atom()}]]></c></tag> + <item> + <p>Module implementing the behaviour <seealso marker="ssh_server_key_api">ssh_server_key_api</seealso>. +diff --git lib/ssh/src/ssh.appup.src lib/ssh/src/ssh.appup.src +index b2b2994..e76c110 100644 +--- lib/ssh/src/ssh.appup.src ++++ lib/ssh/src/ssh.appup.src +@@ -1,7 +1,7 @@ + %% -*- erlang -*- + %% %CopyrightBegin% + %% +-%% Copyright Ericsson AB 2004-2014. All Rights Reserved. ++%% Copyright Ericsson AB 2004-2015. All Rights Reserved. + %% + %% The contents of this file are subject to the Erlang Public License, + %% Version 1.1, (the "License"); you may not use this file except in +@@ -19,61 +19,9 @@ + + {"%VSN%", + [ +- {"3.0.8", [{load_module, ssh_connection, soft_purge, soft_purge, [ssh_connection_handler]}, +- {load_module, ssh_sftp, soft_purge, soft_purge, [ssh_xfer]}, +- {load_module, ssh_connection_handler, soft_purge, soft_purge, []}, +- {load_module, ssh, soft_purge, soft_purge, [ssh_connection_handler]}, +- {load_module, ssh_xfer, soft_purge, soft_purge, []} +- ]}, +- {"3.0.7", [{load_module, ssh_auth, soft_purge, soft_purge, [ssh_connection_handler]}, +- {load_module, ssh_acceptor, soft_purge, soft_purge, [ssh_connection_handler]}, +- {load_module, ssh_channel, soft_purge, soft_purge, [ssh_connection_handler]}, +- {load_module, ssh_connection, soft_purge, soft_purge, [ssh_connection_handler]}, +- {load_module, ssh_connection_handler, soft_purge, soft_purge, []}, +- {load_module, ssh_info, soft_purge, soft_purge, []}, +- {load_module, ssh_message, soft_purge, soft_purge, [ssh_connection_handler]}, +- {load_module, ssh_io, soft_purge, soft_purge, [ssh_connection_handler]}, +- {load_module, ssh_sftp, soft_purge, soft_purge, [ssh_connection_handler]}, +- {load_module, ssh_xfer, soft_purge, soft_purge, [ssh_connection_handler]}]}, +- {"3.0.6", [{load_module, ssh_auth, soft_purge, soft_purge, [ssh_connection_handler]}, +- {load_module, ssh_acceptor, soft_purge, soft_purge, [ssh_connection_handler]}, +- {load_module, ssh_channel, soft_purge, soft_purge, [ssh_connection_handler]}, +- {load_module, ssh_connection, soft_purge, soft_purge, [ssh_connection_handler]}, +- {load_module, ssh_connection_handler, soft_purge, soft_purge, []}, +- {load_module, ssh_info, soft_purge, soft_purge, []}, +- {load_module, ssh_message, soft_purge, soft_purge, [ssh_connection_handler]}, +- {load_module, ssh_io, soft_purge, soft_purge, [ssh_connection_handler]}, +- {load_module, ssh_sftp, soft_purge, soft_purge, [ssh_connection_handler]}, +- {load_module, ssh_xfer, soft_purge, soft_purge, [ssh_connection_handler]}]}, + {<<".*">>, [{restart_application, ssh}]} + ], + [ +- {"3.0.8", [{load_module, ssh_connection, soft_purge, soft_purge, [ssh_connection_handler]}, +- {load_module, ssh_sftp, soft_purge, soft_purge, []}, +- {load_module, ssh_connection_handler, soft_purge, soft_purge, []}, +- {load_module, ssh, soft_purge, soft_purge, []}, +- {load_module, ssh_xfer, soft_purge, soft_purge, []} +- ]}, +- {"3.0.7", [{load_module, ssh_auth, soft_purge, soft_purge, [ssh_connection_handler]}, +- {load_module, ssh_acceptor, soft_purge, soft_purge, [ssh_connection_handler]}, +- {load_module, ssh_channel, soft_purge, soft_purge, [ssh_connection_handler]}, +- {load_module, ssh_connection, soft_purge, soft_purge, [ssh_connection_handler]}, +- {load_module, ssh_connection_handler, soft_purge, soft_purge, []}, +- {load_module, ssh_info, soft_purge, soft_purge, []}, +- {load_module, ssh_message, soft_purge, soft_purge, [ssh_connection_handler]}, +- {load_module, ssh_io, soft_purge, soft_purge, [ssh_connection_handler]}, +- {load_module, ssh_sftp, soft_purge, soft_purge, [ssh_connection_handler]}, +- {load_module, ssh_xfer, soft_purge, soft_purge, [ssh_connection_handler]}]}, +- {"3.0.6", [{load_module, ssh_auth, soft_purge, soft_purge, [ssh_connection_handler]}, +- {load_module, ssh_acceptor, soft_purge, soft_purge, [ssh_connection_handler]}, +- {load_module, ssh_channel, soft_purge, soft_purge, [ssh_connection_handler]}, +- {load_module, ssh_connection, soft_purge, soft_purge, [ssh_connection_handler]}, +- {load_module, ssh_connection_handler, soft_purge, soft_purge, []}, +- {load_module, ssh_info, soft_purge, soft_purge, []}, +- {load_module, ssh_message, soft_purge, soft_purge, [ssh_connection_handler]}, +- {load_module, ssh_io, soft_purge, soft_purge, [ssh_connection_handler]}, +- {load_module, ssh_sftp, soft_purge, soft_purge, [ssh_connection_handler]}, +- {load_module, ssh_xfer, soft_purge, soft_purge, [ssh_connection_handler]}]}, + {<<".*">>, [{restart_application, ssh}]} + ] + }. +diff --git lib/ssh/src/ssh.erl lib/ssh/src/ssh.erl +index eae33e3..51ad691 100644 +--- lib/ssh/src/ssh.erl ++++ lib/ssh/src/ssh.erl +@@ -345,9 +345,14 @@ handle_option([{parallel_login, _} = Opt|Rest], SocketOptions, SshOptions) -> + handle_option(Rest, SocketOptions, [handle_ssh_option(Opt) | SshOptions]); + handle_option([parallel_login|Rest], SocketOptions, SshOptions) -> + handle_option(Rest, SocketOptions, [handle_ssh_option({parallel_login,true}) | SshOptions]); ++handle_option([{minimal_remote_max_packet_size, _} = Opt|Rest], SocketOptions, SshOptions) -> ++ handle_option(Rest, SocketOptions, [handle_ssh_option(Opt) | SshOptions]); + handle_option([Opt | Rest], SocketOptions, SshOptions) -> + handle_option(Rest, [handle_inet_option(Opt) | SocketOptions], SshOptions). + ++ ++handle_ssh_option({minimal_remote_max_packet_size, Value} = Opt) when is_integer(Value), Value >=0 -> ++ Opt; + handle_ssh_option({system_dir, Value} = Opt) when is_list(Value) -> + Opt; + handle_ssh_option({user_dir, Value} = Opt) when is_list(Value) -> +diff --git lib/ssh/src/ssh_acceptor.erl lib/ssh/src/ssh_acceptor.erl +index 6c443ee..34988f1 100644 +--- lib/ssh/src/ssh_acceptor.erl ++++ lib/ssh/src/ssh_acceptor.erl +@@ -1,7 +1,7 @@ + %% + %% %CopyrightBegin% + %% +-%% Copyright Ericsson AB 2008-2013. All Rights Reserved. ++%% Copyright Ericsson AB 2008-2015. All Rights Reserved. + %% + %% The contents of this file are subject to the Erlang Public License, + %% Version 1.1, (the "License"); you may not use this file except in +@@ -43,7 +43,7 @@ start_link(Port, Address, SockOpts, Opts, AcceptTimeout) -> + acceptor_init(Parent, Port, Address, SockOpts, Opts, AcceptTimeout) -> + {_, Callback, _} = + proplists:get_value(transport, Opts, {tcp, gen_tcp, tcp_closed}), +- case (catch do_socket_listen(Callback, Port, SockOpts)) of ++ case (catch do_socket_listen(Callback, Port, [{active, false} | SockOpts])) of + {ok, ListenSocket} -> + proc_lib:init_ack(Parent, {ok, self()}), + acceptor_loop(Callback, +diff --git lib/ssh/src/ssh_connection.erl lib/ssh/src/ssh_connection.erl +index c66f810..654b9d4 100644 +--- lib/ssh/src/ssh_connection.erl ++++ lib/ssh/src/ssh_connection.erl +@@ -1,7 +1,7 @@ + %% + %% %CopyrightBegin% + %% +-%% Copyright Ericsson AB 2008-2014. All Rights Reserved. ++%% Copyright Ericsson AB 2008-2015. All Rights Reserved. + %% + %% The contents of this file are subject to the Erlang Public License, + %% Version 1.1, (the "License"); you may not use this file except in +@@ -326,9 +326,7 @@ channel_data(ChannelId, DataType, Data, + SendDataType, + SendData)} + end, SendList), +- FlowCtrlMsgs = flow_control(Replies, +- Channel, +- Cache), ++ FlowCtrlMsgs = flow_control(Replies, Channel, Cache), + {{replies, Replies ++ FlowCtrlMsgs}, Connection}; + _ -> + gen_fsm:reply(From, {error, closed}), +@@ -470,18 +468,31 @@ handle_msg(#ssh_msg_channel_window_adjust{recipient_channel = ChannelId, + handle_msg(#ssh_msg_channel_open{channel_type = "session" = Type, + sender_channel = RemoteId, + initial_window_size = WindowSz, +- maximum_packet_size = PacketSz}, Connection0, server) -> +- +- try setup_session(Connection0, RemoteId, +- Type, WindowSz, PacketSz) of +- Result -> +- Result +- catch _:_ -> ++ maximum_packet_size = PacketSz}, ++ #connection{options = SSHopts} = Connection0, ++ server) -> ++ MinAcceptedPackSz = proplists:get_value(minimal_remote_max_packet_size, SSHopts, 0), ++ ++ if ++ MinAcceptedPackSz =< PacketSz -> ++ try setup_session(Connection0, RemoteId, ++ Type, WindowSz, PacketSz) of ++ Result -> ++ Result ++ catch _:_ -> ++ FailMsg = channel_open_failure_msg(RemoteId, ++ ?SSH_OPEN_CONNECT_FAILED, ++ "Connection refused", "en"), ++ {{replies, [{connection_reply, FailMsg}]}, ++ Connection0} ++ end; ++ ++ MinAcceptedPackSz > PacketSz -> + FailMsg = channel_open_failure_msg(RemoteId, +- ?SSH_OPEN_CONNECT_FAILED, +- "Connection refused", "en"), +- {{replies, [{connection_reply, FailMsg}]}, +- Connection0} ++ ?SSH_OPEN_ADMINISTRATIVELY_PROHIBITED, ++ lists:concat(["Maximum packet size below ",MinAcceptedPackSz, ++ " not supported"]), "en"), ++ {{replies, [{connection_reply, FailMsg}]}, Connection0} + end; + + handle_msg(#ssh_msg_channel_open{channel_type = "session", +@@ -501,41 +512,57 @@ handle_msg(#ssh_msg_channel_open{channel_type = "forwarded-tcpip" = Type, + initial_window_size = RWindowSz, + maximum_packet_size = RPacketSz, + data = Data}, +- #connection{channel_cache = Cache} = Connection0, server) -> ++ #connection{channel_cache = Cache, ++ options = SSHopts} = Connection0, server) -> + <<?UINT32(ALen), Address:ALen/binary, ?UINT32(Port), + ?UINT32(OLen), Orig:OLen/binary, ?UINT32(OrigPort)>> = Data, + +- case bound_channel(Address, Port, Connection0) of +- undefined -> ++ MinAcceptedPackSz = proplists:get_value(minimal_remote_max_packet_size, SSHopts, 0), ++ ++ if ++ MinAcceptedPackSz =< RPacketSz -> ++ case bound_channel(Address, Port, Connection0) of ++ undefined -> ++ FailMsg = channel_open_failure_msg(RemoteId, ++ ?SSH_OPEN_CONNECT_FAILED, ++ "Connection refused", "en"), ++ {{replies, ++ [{connection_reply, FailMsg}]}, Connection0}; ++ ChannelPid -> ++ {ChannelId, Connection1} = new_channel_id(Connection0), ++ LWindowSz = ?DEFAULT_WINDOW_SIZE, ++ LPacketSz = ?DEFAULT_PACKET_SIZE, ++ Channel = #channel{type = Type, ++ sys = "none", ++ user = ChannelPid, ++ local_id = ChannelId, ++ recv_window_size = LWindowSz, ++ recv_packet_size = LPacketSz, ++ send_window_size = RWindowSz, ++ send_packet_size = RPacketSz, ++ send_buf = queue:new() ++ }, ++ ssh_channel:cache_update(Cache, Channel), ++ OpenConfMsg = channel_open_confirmation_msg(RemoteId, ChannelId, ++ LWindowSz, LPacketSz), ++ {OpenMsg, Connection} = ++ reply_msg(Channel, Connection1, ++ {open, Channel, {forwarded_tcpip, ++ decode_ip(Address), Port, ++ decode_ip(Orig), OrigPort}}), ++ {{replies, [{connection_reply, OpenConfMsg}, ++ OpenMsg]}, Connection} ++ end; ++ ++ MinAcceptedPackSz > RPacketSz -> + FailMsg = channel_open_failure_msg(RemoteId, +- ?SSH_OPEN_CONNECT_FAILED, +- "Connection refused", "en"), +- {{replies, +- [{connection_reply, FailMsg}]}, Connection0}; +- ChannelPid -> +- {ChannelId, Connection1} = new_channel_id(Connection0), +- LWindowSz = ?DEFAULT_WINDOW_SIZE, +- LPacketSz = ?DEFAULT_PACKET_SIZE, +- Channel = #channel{type = Type, +- sys = "none", +- user = ChannelPid, +- local_id = ChannelId, +- recv_window_size = LWindowSz, +- recv_packet_size = LPacketSz, +- send_window_size = RWindowSz, +- send_packet_size = RPacketSz}, +- ssh_channel:cache_update(Cache, Channel), +- OpenConfMsg = channel_open_confirmation_msg(RemoteId, ChannelId, +- LWindowSz, LPacketSz), +- {OpenMsg, Connection} = +- reply_msg(Channel, Connection1, +- {open, Channel, {forwarded_tcpip, +- decode_ip(Address), Port, +- decode_ip(Orig), OrigPort}}), +- {{replies, [{connection_reply, OpenConfMsg}, +- OpenMsg]}, Connection} ++ ?SSH_OPEN_ADMINISTRATIVELY_PROHIBITED, ++ lists:concat(["Maximum packet size below ",MinAcceptedPackSz, ++ " not supported"]), "en"), ++ {{replies, [{connection_reply, FailMsg}]}, Connection0} + end; + ++ + handle_msg(#ssh_msg_channel_open{channel_type = "forwarded-tcpip", + sender_channel = RemoteId}, + Connection, client) -> +@@ -917,7 +944,8 @@ start_channel(Cb, Id, Args, SubSysSup, Exec) -> + %%-------------------------------------------------------------------- + %%% Internal functions + %%-------------------------------------------------------------------- +-setup_session(#connection{channel_cache = Cache} = Connection0, ++setup_session(#connection{channel_cache = Cache ++ } = Connection0, + RemoteId, + Type, WindowSize, PacketSize) -> + {ChannelId, Connection} = new_channel_id(Connection0), +@@ -929,6 +957,7 @@ setup_session(#connection{channel_cache = Cache} = Connection0, + recv_packet_size = ?DEFAULT_PACKET_SIZE, + send_window_size = WindowSize, + send_packet_size = PacketSize, ++ send_buf = queue:new(), + remote_id = RemoteId + }, + ssh_channel:cache_update(Cache, Channel), +@@ -1024,63 +1053,74 @@ request_reply_or_data(#channel{local_id = ChannelId, user = ChannelPid}, + + update_send_window(Channel, _, undefined, + #connection{channel_cache = Cache}) -> +- do_update_send_window(Channel, Channel#channel.send_buf, Cache); ++ do_update_send_window(Channel, Cache); + +-update_send_window(Channel, DataType, Data, ++update_send_window(#channel{send_buf = SendBuffer} = Channel, DataType, Data, + #connection{channel_cache = Cache}) -> +- do_update_send_window(Channel, Channel#channel.send_buf ++ [{DataType, Data}], Cache). ++ do_update_send_window(Channel#channel{send_buf = queue:in({DataType, Data}, SendBuffer)}, ++ Cache). + +-do_update_send_window(Channel0, Buf0, Cache) -> +- {Buf1, NewSz, Buf2} = get_window(Buf0, +- Channel0#channel.send_packet_size, +- Channel0#channel.send_window_size), +- +- Channel = Channel0#channel{send_window_size = NewSz, send_buf = Buf2}, ++do_update_send_window(Channel0, Cache) -> ++ {SendMsgs, Channel} = get_window(Channel0, []), + ssh_channel:cache_update(Cache, Channel), +- {Buf1, Channel}. ++ {SendMsgs, Channel}. + +-get_window(Bs, PSz, WSz) -> +- get_window(Bs, PSz, WSz, []). +- +-get_window(Bs, _PSz, 0, Acc) -> +- {lists:reverse(Acc), 0, Bs}; +-get_window([B0 = {DataType, Bin} | Bs], PSz, WSz, Acc) -> +- BSz = size(Bin), +- if BSz =< WSz -> %% will fit into window +- if BSz =< PSz -> %% will fit into a packet +- get_window(Bs, PSz, WSz-BSz, [B0|Acc]); +- true -> %% split into packet size +- <<Bin1:PSz/binary, Bin2/binary>> = Bin, +- get_window([setelement(2, B0, Bin2) | Bs], +- PSz, WSz-PSz, +- [{DataType, Bin1}|Acc]) ++get_window(#channel{send_window_size = 0 ++ } = Channel, Acc) -> ++ {lists:reverse(Acc), Channel}; ++get_window(#channel{send_packet_size = 0 ++ } = Channel, Acc) -> ++ {lists:reverse(Acc), Channel}; ++get_window(#channel{send_buf = Buffer, ++ send_packet_size = PacketSize, ++ send_window_size = WindowSize0 ++ } = Channel, Acc0) -> ++ case queue:out(Buffer) of ++ {{value, {_, Data} = Msg}, NewBuffer} -> ++ case handle_send_window(Msg, size(Data), PacketSize, WindowSize0, Acc0) of ++ {WindowSize, Acc, {_, <<>>}} -> ++ {lists:reverse(Acc), Channel#channel{send_window_size = WindowSize, ++ send_buf = NewBuffer}}; ++ {WindowSize, Acc, Rest} -> ++ get_window(Channel#channel{send_window_size = WindowSize, ++ send_buf = queue:in_r(Rest, NewBuffer)}, Acc) + end; +- WSz =< PSz -> %% use rest of window +- <<Bin1:WSz/binary, Bin2/binary>> = Bin, +- get_window([setelement(2, B0, Bin2) | Bs], +- PSz, WSz-WSz, +- [{DataType, Bin1}|Acc]); +- true -> %% use packet size +- <<Bin1:PSz/binary, Bin2/binary>> = Bin, +- get_window([setelement(2, B0, Bin2) | Bs], +- PSz, WSz-PSz, +- [{DataType, Bin1}|Acc]) ++ {empty, NewBuffer} -> ++ {[], Channel#channel{send_buf = NewBuffer}} ++ end. ++ ++handle_send_window(Msg = {Type, Data}, Size, PacketSize, WindowSize, Acc) when Size =< WindowSize -> ++ case Size =< PacketSize of ++ true -> ++ {WindowSize - Size, [Msg | Acc], {Type, <<>>}}; ++ false -> ++ <<Msg1:PacketSize/binary, Msg2/binary>> = Data, ++ {WindowSize - PacketSize, [{Type, Msg1} | Acc], {Type, Msg2}} + end; +-get_window([], _PSz, WSz, Acc) -> +- {lists:reverse(Acc), WSz, []}. ++handle_send_window({Type, Data}, _, PacketSize, WindowSize, Acc) when WindowSize =< PacketSize -> ++ <<Msg1:WindowSize/binary, Msg2/binary>> = Data, ++ {WindowSize - WindowSize, [{Type, Msg1} | Acc], {Type, Msg2}}; ++handle_send_window({Type, Data}, _, PacketSize, WindowSize, Acc) -> ++ <<Msg1:PacketSize/binary, Msg2/binary>> = Data, ++ {WindowSize - PacketSize, [{Type, Msg1} | Acc], {Type, Msg2}}. + + flow_control(Channel, Cache) -> + flow_control([window_adjusted], Channel, Cache). +- ++ + flow_control([], Channel, Cache) -> + ssh_channel:cache_update(Cache, Channel), + []; +- + flow_control([_|_], #channel{flow_control = From, +- send_buf = []} = Channel, Cache) when From =/= undefined -> +- [{flow_control, Cache, Channel, From, ok}]; ++ send_buf = Buffer} = Channel, Cache) when From =/= undefined -> ++ case queue:is_empty(Buffer) of ++ true -> ++ ssh_channel:cache_update(Cache, Channel#channel{flow_control = undefined}), ++ [{flow_control, Cache, Channel, From, ok}]; ++ false -> ++ [] ++ end; + flow_control(_,_,_) -> +- []. ++ []. + + pty_req(ConnectionHandler, Channel, Term, Width, Height, + PixWidth, PixHeight, PtyOpts, TimeOut) -> +diff --git lib/ssh/src/ssh_connection_handler.erl lib/ssh/src/ssh_connection_handler.erl +index 68523aa..e1f2e05 100644 +--- lib/ssh/src/ssh_connection_handler.erl ++++ lib/ssh/src/ssh_connection_handler.erl +@@ -1,7 +1,7 @@ + %% + %% %CopyrightBegin% + %% +-%% Copyright Ericsson AB 2008-2014. All Rights Reserved. ++%% Copyright Ericsson AB 2008-2015. All Rights Reserved. + %% + %% The contents of this file are subject to the Erlang Public License, + %% Version 1.1, (the "License"); you may not use this file except in +@@ -751,7 +751,9 @@ handle_sync_event({open, ChannelPid, Type, InitialWindowSize, MaxPacketSize, Dat + user = ChannelPid, + local_id = ChannelId, + recv_window_size = InitialWindowSize, +- recv_packet_size = MaxPacketSize}, ++ recv_packet_size = MaxPacketSize, ++ send_buf = queue:new() ++ }, + ssh_channel:cache_update(Cache, Channel), + State = add_request(true, ChannelId, From, State2), + start_timeout(ChannelId, From, Timeout), +@@ -1241,10 +1243,9 @@ event(Event, StateName, State) -> + handle_disconnect(DisconnectMsg, State); + throw:{ErrorToDisplay, #ssh_msg_disconnect{} = DisconnectMsg} -> + handle_disconnect(DisconnectMsg, State, ErrorToDisplay); +- _:Error -> +- log_error(Error), ++ _:_ -> + handle_disconnect(#ssh_msg_disconnect{code = error_code(StateName), +- description = "Internal error", ++ description = "Invalid state", + language = "en"}, State) + end. + error_code(key_exchange) -> +diff --git lib/ssh/src/ssh_info.erl lib/ssh/src/ssh_info.erl +index 9a91875..30df32c 100644 +--- lib/ssh/src/ssh_info.erl ++++ lib/ssh/src/ssh_info.erl +@@ -27,18 +27,21 @@ + -compile(export_all). + + print() -> ++ print(user). ++ ++print(D) -> + try supervisor:which_children(ssh_sup) + of + _ -> +- io:nl(), +- print_general(), +- io:nl(), +- underline("Client part", $=), +- print_clients(), +- io:nl(), +- underline("Server part", $=), +- print_servers(), +- io:nl(), ++ io:nl(D), ++ print_general(D), ++ io:nl(D), ++ underline(D, "Client part", $=), ++ print_clients(D), ++ io:nl(D), ++ underline(D, "Server part", $=), ++ print_servers(D), ++ io:nl(D), + %% case os:type() of + %% {unix,_} -> + %% io:nl(), +@@ -50,90 +53,95 @@ print() -> + %% catch io:format(os:cmd("netstat -tpn")); + %% _ -> ok + %% end, +- underline("Supervisors", $=), +- walk_sups(ssh_sup), +- io:nl() ++ underline(D, "Supervisors", $=), ++ walk_sups(D, ssh_sup), ++ io:nl(D) + catch + _:_ -> +- io:format("Ssh not found~n",[]) ++ io:format(D,"Ssh not found~n",[]) + end. + + %%%================================================================ +-print_general() -> ++print_general(D) -> + {_Name, Slogan, Ver} = lists:keyfind(ssh,1,application:which_applications()), +- underline(io_lib:format("~s ~s", [Slogan, Ver]), $=), +- io:format('This printout is generated ~s. ~n',[datetime()]). ++ underline(D, io_lib:format("~s ~s", [Slogan, Ver]), $=), ++ io:format(D, 'This printout is generated ~s. ~n',[datetime()]). + + %%%================================================================ +-print_clients() -> ++print_clients(D) -> ++ PrintClient = fun(X) -> print_client(D,X) end, + try +- lists:foreach(fun print_client/1, supervisor:which_children(sshc_sup)) ++ lists:foreach(PrintClient, supervisor:which_children(sshc_sup)) + catch + C:E -> +- io:format('***FAILED: ~p:~p~n',[C,E]) ++ io:format(D, '***FAILED: ~p:~p~n',[C,E]) + end. + +-print_client({undefined,Pid,supervisor,[ssh_connection_handler]}) -> ++print_client(D, {undefined,Pid,supervisor,[ssh_connection_handler]}) -> + {{Local,Remote},_Str} = ssh_connection_handler:get_print_info(Pid), +- io:format(" Local=~s Remote=~s~n",[fmt_host_port(Local),fmt_host_port(Remote)]); +-print_client(Other) -> +- io:format(" [[Other 1: ~p]]~n",[Other]). ++ io:format(D, " Local=~s Remote=~s~n",[fmt_host_port(Local),fmt_host_port(Remote)]); ++print_client(D, Other) -> ++ io:format(D, " [[Other 1: ~p]]~n",[Other]). + + + %%%================================================================ +-print_servers() -> ++print_servers(D) -> ++ PrintServer = fun(X) -> print_server(D,X) end, + try +- lists:foreach(fun print_server/1, supervisor:which_children(sshd_sup)) ++ lists:foreach(PrintServer, supervisor:which_children(sshd_sup)) + catch + C:E -> +- io:format('***FAILED: ~p:~p~n',[C,E]) ++ io:format(D, '***FAILED: ~p:~p~n',[C,E]) + end. + +-print_server({{server,ssh_system_sup,LocalHost,LocalPort},Pid,supervisor,[ssh_system_sup]}) when is_pid(Pid) -> +- io:format('Local=~s (~p children)~n',[fmt_host_port({LocalHost,LocalPort}), +- ssh_acceptor:number_of_connections(Pid)]), +- lists:foreach(fun print_system_sup/1, supervisor:which_children(Pid)); +-print_server(Other) -> +- io:format(" [[Other 2: ~p]]~n",[Other]). ++print_server(D, {{server,ssh_system_sup,LocalHost,LocalPort},Pid,supervisor,[ssh_system_sup]}) when is_pid(Pid) -> ++ io:format(D, 'Local=~s (~p children)~n',[fmt_host_port({LocalHost,LocalPort}), ++ ssh_acceptor:number_of_connections(Pid)]), ++ PrintSystemSup = fun(X) -> print_system_sup(D,X) end, ++ lists:foreach(PrintSystemSup, supervisor:which_children(Pid)); ++print_server(D, Other) -> ++ io:format(D, " [[Other 2: ~p]]~n",[Other]). + +-print_system_sup({Ref,Pid,supervisor,[ssh_subsystem_sup]}) when is_reference(Ref), ++print_system_sup(D, {Ref,Pid,supervisor,[ssh_subsystem_sup]}) when is_reference(Ref), + is_pid(Pid) -> +- lists:foreach(fun print_channels/1, supervisor:which_children(Pid)); +-print_system_sup({{ssh_acceptor_sup,LocalHost,LocalPort}, Pid,supervisor, [ssh_acceptor_sup]}) when is_pid(Pid) -> +- io:format(" [Acceptor for ~s]~n",[fmt_host_port({LocalHost,LocalPort})]); +-print_system_sup(Other) -> +- io:format(" [[Other 3: ~p]]~n",[Other]). ++ PrintChannels = fun(X) -> print_channels(D,X) end, ++ lists:foreach(PrintChannels, supervisor:which_children(Pid)); ++print_system_sup(D, {{ssh_acceptor_sup,LocalHost,LocalPort}, Pid,supervisor, [ssh_acceptor_sup]}) when is_pid(Pid) -> ++ io:format(D, " [Acceptor for ~s]~n",[fmt_host_port({LocalHost,LocalPort})]); ++print_system_sup(D, Other) -> ++ io:format(D, " [[Other 3: ~p]]~n",[Other]). + +-print_channels({{server,ssh_channel_sup,_,_},Pid,supervisor,[ssh_channel_sup]}) when is_pid(Pid) -> +- lists:foreach(fun print_channel/1, supervisor:which_children(Pid)); +-print_channels(Other) -> +- io:format(" [[Other 4: ~p]]~n",[Other]). ++print_channels(D, {{server,ssh_channel_sup,_,_},Pid,supervisor,[ssh_channel_sup]}) when is_pid(Pid) -> ++ PrintChannel = fun(X) -> print_channel(D,X) end, ++ lists:foreach(PrintChannel, supervisor:which_children(Pid)); ++print_channels(D, Other) -> ++ io:format(D, " [[Other 4: ~p]]~n",[Other]). + + +-print_channel({Ref,Pid,worker,[ssh_channel]}) when is_reference(Ref), +- is_pid(Pid) -> ++print_channel(D, {Ref,Pid,worker,[ssh_channel]}) when is_reference(Ref), ++ is_pid(Pid) -> + {{ConnManager,ChannelID}, Str} = ssh_channel:get_print_info(Pid), + {{Local,Remote},StrM} = ssh_connection_handler:get_print_info(ConnManager), +- io:format(' ch ~p: ~s ~s',[ChannelID, StrM, Str]), +- io:format(" Local=~s Remote=~s~n",[fmt_host_port(Local),fmt_host_port(Remote)]); +-print_channel(Other) -> +- io:format(" [[Other 5: ~p]]~n",[Other]). ++ io:format(D, ' ch ~p: ~s ~s',[ChannelID, StrM, Str]), ++ io:format(D, " Local=~s Remote=~s~n",[fmt_host_port(Local),fmt_host_port(Remote)]); ++print_channel(D, Other) -> ++ io:format(D, " [[Other 5: ~p]]~n",[Other]). + + %%%================================================================ + -define(inc(N), (N+4)). + +-walk_sups(StartPid) -> +- io:format("Start at ~p, ~s.~n",[StartPid,dead_or_alive(StartPid)]), +- walk_sups(children(StartPid), _Indent=?inc(0)). ++walk_sups(D, StartPid) -> ++ io:format(D, "Start at ~p, ~s.~n",[StartPid,dead_or_alive(StartPid)]), ++ walk_sups(D, children(StartPid), _Indent=?inc(0)). + +-walk_sups([H={_,Pid,SupOrWorker,_}|T], Indent) -> +- indent(Indent), io:format('~200p ~p is ~s~n',[H,Pid,dead_or_alive(Pid)]), ++walk_sups(D, [H={_,Pid,SupOrWorker,_}|T], Indent) -> ++ indent(D, Indent), io:format(D, '~200p ~p is ~s~n',[H,Pid,dead_or_alive(Pid)]), + case SupOrWorker of +- supervisor -> walk_sups(children(Pid), ?inc(Indent)); ++ supervisor -> walk_sups(D, children(Pid), ?inc(Indent)); + _ -> ok + end, +- walk_sups(T, Indent); +-walk_sups([], _) -> ++ walk_sups(D, T, Indent); ++walk_sups(_D, [], _) -> + ok. + + dead_or_alive(Name) when is_atom(Name) -> +@@ -149,7 +157,7 @@ dead_or_alive(Pid) when is_pid(Pid) -> + _ -> "alive" + end. + +-indent(I) -> io:format('~*c',[I,$ ]). ++indent(D, I) -> io:format(D,'~*c',[I,$ ]). + + children(Pid) -> + Parent = self(), +@@ -166,16 +174,16 @@ children(Pid) -> + end. + + %%%================================================================ +-underline(Str) -> +- underline(Str, $-). ++underline(D, Str) -> ++ underline(D, Str, $-). + +-underline(Str, LineChar) -> ++underline(D, Str, LineChar) -> + Len = lists:flatlength(Str), +- io:format('~s~n',[Str]), +- line(Len,LineChar). ++ io:format(D, '~s~n',[Str]), ++ line(D,Len,LineChar). + +-line(Len, Char) -> +- io:format('~*c~n', [Len,Char]). ++line(D, Len, Char) -> ++ io:format(D, '~*c~n', [Len,Char]). + + + datetime() -> +@@ -188,6 +196,6 @@ fmt_host_port({Host,Port}) -> io_lib:format('~s:~p',[Host,Port]). + + + +-nyi() -> +- io:format('Not yet implemented~n',[]), ++nyi(D) -> ++ io:format(D,'Not yet implemented~n',[]), + nyi. +diff --git lib/ssh/test/ssh_basic_SUITE.erl lib/ssh/test/ssh_basic_SUITE.erl +index 45c0303..81c7b5c 100644 +--- lib/ssh/test/ssh_basic_SUITE.erl ++++ lib/ssh/test/ssh_basic_SUITE.erl +@@ -50,6 +50,8 @@ all() -> + double_close, + ssh_connect_timeout, + ssh_connect_arg4_timeout, ++ packet_size_zero, ++ ssh_daemon_minimal_remote_max_packet_size_option, + {group, hardening_tests} + ]. + +@@ -757,6 +759,64 @@ ms_passed(N1={_,_,M1}, N2={_,_,M2}) -> + 1000 * (Min*60 + Sec + (M2-M1)/1000000). + + %%-------------------------------------------------------------------- ++packet_size_zero(Config) -> ++ SystemDir = ?config(data_dir, Config), ++ PrivDir = ?config(priv_dir, Config), ++ UserDir = filename:join(PrivDir, nopubkey), % to make sure we don't use public-key-auth ++ file:make_dir(UserDir), ++ ++ {Server, Host, Port} = ssh_test_lib:daemon([{system_dir, SystemDir}, ++ {user_dir, UserDir}, ++ {user_passwords, [{"vego", "morot"}]}]), ++ Conn = ++ ssh_test_lib:connect(Host, Port, [{silently_accept_hosts, true}, ++ {user_dir, UserDir}, ++ {user_interaction, false}, ++ {user, "vego"}, ++ {password, "morot"}]), ++ ++ {ok,Chan} = ssh_connection:session_channel(Conn, 1000, _MaxPacketSize=0, 60000), ++ ok = ssh_connection:shell(Conn, Chan), ++ ++ ssh:close(Conn), ++ ssh:stop_daemon(Server), ++ ++ receive ++ {ssh_cm,Conn,{data,Chan,_Type,_Msg1}} = M -> ++ ct:pal("Got ~p",[M]), ++ ct:fail(doesnt_obey_max_packet_size_0) ++ after 5000 -> ++ ok ++ end. ++ ++%%-------------------------------------------------------------------- ++ssh_daemon_minimal_remote_max_packet_size_option(Config) -> ++ SystemDir = ?config(data_dir, Config), ++ PrivDir = ?config(priv_dir, Config), ++ UserDir = filename:join(PrivDir, nopubkey), % to make sure we don't use public-key-auth ++ file:make_dir(UserDir), ++ ++ {Server, Host, Port} = ssh_test_lib:daemon([{system_dir, SystemDir}, ++ {user_dir, UserDir}, ++ {user_passwords, [{"vego", "morot"}]}, ++ {failfun, fun ssh_test_lib:failfun/2}, ++ {minimal_remote_max_packet_size, 14}]), ++ Conn = ++ ssh_test_lib:connect(Host, Port, [{silently_accept_hosts, true}, ++ {user_dir, UserDir}, ++ {user_interaction, false}, ++ {user, "vego"}, ++ {password, "morot"}]), ++ ++ %% Try the limits of the minimal_remote_max_packet_size: ++ {ok, _ChannelId} = ssh_connection:session_channel(Conn, 100, 14, infinity), ++ {open_error,_,"Maximum packet size below 14 not supported",_} = ++ ssh_connection:session_channel(Conn, 100, 13, infinity), ++ ++ ssh:close(Conn), ++ ssh:stop_daemon(Server). ++ ++%%-------------------------------------------------------------------- + ssh_connect_negtimeout_parallel(Config) -> ssh_connect_negtimeout(Config,true). + ssh_connect_negtimeout_sequential(Config) -> ssh_connect_negtimeout(Config,false). + +@@ -970,7 +1030,7 @@ max_sessions(Config, ParallelLogin, Connect0) when is_function(Connect0,2) -> + + %% Due to timing the error message may or may not be delivered to + %% the "tcp-application" before the socket closed message is recived +-check_error("Internal error") -> ++check_error("Invalid state") -> + ok; + check_error("Connection closed") -> + ok; +diff --git lib/ssh/vsn.mk lib/ssh/vsn.mk +index 0d90278..fec8dac 100644 +--- lib/ssh/vsn.mk ++++ lib/ssh/vsn.mk +@@ -1,5 +1,4 @@ + #-*-makefile-*- ; force emacs to enter makefile-mode + +-SSH_VSN = 3.2 ++SSH_VSN = 3.2.1 + APP_VSN = "ssh-$(SSH_VSN)" +- +diff --git otp_versions.table otp_versions.table +index 64ffd82..a82f535 100644 +--- otp_versions.table ++++ otp_versions.table +@@ -1,3 +1,4 @@ ++OTP-17.5.1 : ssh-3.2.1 # asn1-3.0.4 common_test-1.10 compiler-5.0.4 cosEvent-2.1.15 cosEventDomain-1.1.14 cosFileTransfer-1.1.16 cosNotification-1.1.21 cosProperty-1.1.17 cosTime-1.1.14 cosTransactions-1.2.14 crypto-3.5 debugger-4.0.3 dialyzer-2.7.4 diameter-1.9 edoc-0.7.16 eldap-1.1.1 erl_docgen-0.3.7 erl_interface-3.7.20 erts-6.4 et-1.5 eunit-2.2.9 gs-1.5.16 hipe-3.11.3 ic-4.3.6 inets-5.10.6 jinterface-1.5.12 kernel-3.2 megaco-3.17.3 mnesia-4.12.5 observer-2.0.4 odbc-2.10.22 orber-3.7.1 os_mon-2.3.1 ose-1.0.2 otp_mibs-1.0.10 parsetools-2.0.12 percept-0.8.10 public_key-0.23 reltool-0.6.6 runtime_tools-1.8.16 sasl-2.4.1 snmp-5.1.1 ssl-6.0 stdlib-2.4 syntax_tools-1.6.18 test_server-3.8 tools-2.7.2 typer-0.9.8 webtool-0.8.10 wx-1.3.3 xmerl-1.3.7 : + OTP-17.5 : asn1-3.0.4 common_test-1.10 compiler-5.0.4 crypto-3.5 debugger-4.0.3 dialyzer-2.7.4 diameter-1.9 eldap-1.1.1 erts-6.4 hipe-3.11.3 inets-5.10.6 kernel-3.2 mnesia-4.12.5 observer-2.0.4 os_mon-2.3.1 public_key-0.23 runtime_tools-1.8.16 ssh-3.2 ssl-6.0 stdlib-2.4 syntax_tools-1.6.18 test_server-3.8 tools-2.7.2 wx-1.3.3 # cosEvent-2.1.15 cosEventDomain-1.1.14 cosFileTransfer-1.1.16 cosNotification-1.1.21 cosProperty-1.1.17 cosTime-1.1.14 cosTransactions-1.2.14 edoc-0.7.16 erl_docgen-0.3.7 erl_interface-3.7.20 et-1.5 eunit-2.2.9 gs-1.5.16 ic-4.3.6 jinterface-1.5.12 megaco-3.17.3 odbc-2.10.22 orber-3.7.1 ose-1.0.2 otp_mibs-1.0.10 parsetools-2.0.12 percept-0.8.10 reltool-0.6.6 sasl-2.4.1 snmp-5.1.1 typer-0.9.8 webtool-0.8.10 xmerl-1.3.7 : + OTP-17.4.1 : erts-6.3.1 inets-5.10.5 # asn1-3.0.3 common_test-1.9 compiler-5.0.3 cosEvent-2.1.15 cosEventDomain-1.1.14 cosFileTransfer-1.1.16 cosNotification-1.1.21 cosProperty-1.1.17 cosTime-1.1.14 cosTransactions-1.2.14 crypto-3.4.2 debugger-4.0.2 dialyzer-2.7.3 diameter-1.8 edoc-0.7.16 eldap-1.1 erl_docgen-0.3.7 erl_interface-3.7.20 et-1.5 eunit-2.2.9 gs-1.5.16 hipe-3.11.2 ic-4.3.6 jinterface-1.5.12 kernel-3.1 megaco-3.17.3 mnesia-4.12.4 observer-2.0.3 odbc-2.10.22 orber-3.7.1 os_mon-2.3 ose-1.0.2 otp_mibs-1.0.10 parsetools-2.0.12 percept-0.8.10 public_key-0.22.1 reltool-0.6.6 runtime_tools-1.8.15 sasl-2.4.1 snmp-5.1.1 ssh-3.1 ssl-5.3.8 stdlib-2.3 syntax_tools-1.6.17 test_server-3.7.2 tools-2.7.1 typer-0.9.8 webtool-0.8.10 wx-1.3.2 xmerl-1.3.7 : + OTP-17.4 : asn1-3.0.3 common_test-1.9 compiler-5.0.3 crypto-3.4.2 debugger-4.0.2 dialyzer-2.7.3 diameter-1.8 edoc-0.7.16 eldap-1.1 erl_docgen-0.3.7 erl_interface-3.7.20 erts-6.3 eunit-2.2.9 hipe-3.11.2 inets-5.10.4 jinterface-1.5.12 kernel-3.1 megaco-3.17.3 mnesia-4.12.4 observer-2.0.3 odbc-2.10.22 otp_mibs-1.0.10 parsetools-2.0.12 percept-0.8.10 runtime_tools-1.8.15 snmp-5.1.1 ssh-3.1 ssl-5.3.8 stdlib-2.3 syntax_tools-1.6.17 test_server-3.7.2 tools-2.7.1 wx-1.3.2 # cosEvent-2.1.15 cosEventDomain-1.1.14 cosFileTransfer-1.1.16 cosNotification-1.1.21 cosProperty-1.1.17 cosTime-1.1.14 cosTransactions-1.2.14 et-1.5 gs-1.5.16 ic-4.3.6 orber-3.7.1 os_mon-2.3 ose-1.0.2 public_key-0.22.1 reltool-0.6.6 sasl-2.4.1 typer-0.9.8 webtool-0.8.10 xmerl-1.3.7 : |