Junio C Hamano | 49a52b1 | 2006-09-10 01:06:33 -0700 | [diff] [blame] | 1 | #include "pkt-line.h" |
| 2 | #include "sideband.h" |
| 3 | |
| 4 | /* |
| 5 | * Receive multiplexed output stream over git native protocol. |
| 6 | * in_stream is the input stream from the remote, which carries data |
| 7 | * in pkt_line format with band designator. Demultiplex it into out |
| 8 | * and err and return error appropriately. Band #1 carries the |
| 9 | * primary payload. Things coming over band #2 is not necessarily |
| 10 | * error; they are usually informative message on the standard error |
| 11 | * stream, aka "verbose"). A message over band #3 is a signal that |
| 12 | * the remote died unexpectedly. A flush() concludes the stream. |
| 13 | */ |
Nicolas Pitre | ebe8fa7 | 2007-11-04 00:22:42 -0400 | [diff] [blame] | 14 | |
| 15 | #define PREFIX "remote:" |
Johannes Sixt | 13e4760 | 2008-01-08 17:24:53 +0100 | [diff] [blame] | 16 | |
| 17 | #define ANSI_SUFFIX "\033[K" |
| 18 | #define DUMB_SUFFIX " " |
| 19 | |
| 20 | #define FIX_SIZE 10 /* large enough for any of the above */ |
Nicolas Pitre | ebe8fa7 | 2007-11-04 00:22:42 -0400 | [diff] [blame] | 21 | |
Johannes Sixt | 34df8ab | 2009-03-10 22:54:17 +0100 | [diff] [blame] | 22 | int recv_sideband(const char *me, int in_stream, int out) |
Junio C Hamano | 49a52b1 | 2006-09-10 01:06:33 -0700 | [diff] [blame] | 23 | { |
Nicolas Pitre | ebe8fa7 | 2007-11-04 00:22:42 -0400 | [diff] [blame] | 24 | unsigned pf = strlen(PREFIX); |
Johannes Sixt | 13e4760 | 2008-01-08 17:24:53 +0100 | [diff] [blame] | 25 | unsigned sf; |
| 26 | char buf[LARGE_PACKET_MAX + 2*FIX_SIZE]; |
| 27 | char *suffix, *term; |
Nicolas Pitre | 6b9c42b | 2008-09-03 15:13:42 -0400 | [diff] [blame] | 28 | int skip_pf = 0; |
Johannes Sixt | 13e4760 | 2008-01-08 17:24:53 +0100 | [diff] [blame] | 29 | |
Nicolas Pitre | ebe8fa7 | 2007-11-04 00:22:42 -0400 | [diff] [blame] | 30 | memcpy(buf, PREFIX, pf); |
Johannes Sixt | 13e4760 | 2008-01-08 17:24:53 +0100 | [diff] [blame] | 31 | term = getenv("TERM"); |
| 32 | if (term && strcmp(term, "dumb")) |
| 33 | suffix = ANSI_SUFFIX; |
| 34 | else |
| 35 | suffix = DUMB_SUFFIX; |
| 36 | sf = strlen(suffix); |
| 37 | |
Junio C Hamano | 49a52b1 | 2006-09-10 01:06:33 -0700 | [diff] [blame] | 38 | while (1) { |
Nicolas Pitre | 9ac13ec | 2006-10-11 11:49:15 -0400 | [diff] [blame] | 39 | int band, len; |
Nicolas Pitre | ebe8fa7 | 2007-11-04 00:22:42 -0400 | [diff] [blame] | 40 | len = packet_read_line(in_stream, buf + pf, LARGE_PACKET_MAX); |
Junio C Hamano | 49a52b1 | 2006-09-10 01:06:33 -0700 | [diff] [blame] | 41 | if (len == 0) |
| 42 | break; |
| 43 | if (len < 1) { |
Johannes Sixt | 34df8ab | 2009-03-10 22:54:17 +0100 | [diff] [blame] | 44 | fprintf(stderr, "%s: protocol error: no band designator\n", me); |
Junio C Hamano | 49a52b1 | 2006-09-10 01:06:33 -0700 | [diff] [blame] | 45 | return SIDEBAND_PROTOCOL_ERROR; |
| 46 | } |
Nicolas Pitre | ebe8fa7 | 2007-11-04 00:22:42 -0400 | [diff] [blame] | 47 | band = buf[pf] & 0xff; |
Junio C Hamano | 49a52b1 | 2006-09-10 01:06:33 -0700 | [diff] [blame] | 48 | len--; |
Nicolas Pitre | 9ac13ec | 2006-10-11 11:49:15 -0400 | [diff] [blame] | 49 | switch (band) { |
Junio C Hamano | 49a52b1 | 2006-09-10 01:06:33 -0700 | [diff] [blame] | 50 | case 3: |
Nicolas Pitre | ebe8fa7 | 2007-11-04 00:22:42 -0400 | [diff] [blame] | 51 | buf[pf] = ' '; |
Johannes Sixt | 34df8ab | 2009-03-10 22:54:17 +0100 | [diff] [blame] | 52 | buf[pf+1+len] = '\0'; |
| 53 | fprintf(stderr, "%s\n", buf); |
Junio C Hamano | 49a52b1 | 2006-09-10 01:06:33 -0700 | [diff] [blame] | 54 | return SIDEBAND_REMOTE_ERROR; |
| 55 | case 2: |
Nicolas Pitre | ebe8fa7 | 2007-11-04 00:22:42 -0400 | [diff] [blame] | 56 | buf[pf] = ' '; |
Nicolas Pitre | 6b9c42b | 2008-09-03 15:13:42 -0400 | [diff] [blame] | 57 | do { |
| 58 | char *b = buf; |
| 59 | int brk = 0; |
Nicolas Pitre | ebe8fa7 | 2007-11-04 00:22:42 -0400 | [diff] [blame] | 60 | |
Nicolas Pitre | 6b9c42b | 2008-09-03 15:13:42 -0400 | [diff] [blame] | 61 | /* |
| 62 | * If the last buffer didn't end with a line |
| 63 | * break then we should not print a prefix |
| 64 | * this time around. |
| 65 | */ |
| 66 | if (skip_pf) { |
| 67 | b += pf+1; |
| 68 | } else { |
| 69 | len += pf+1; |
| 70 | brk += pf+1; |
| 71 | } |
| 72 | |
| 73 | /* Look for a line break. */ |
| 74 | for (;;) { |
Nicolas Pitre | ed1902e | 2007-10-16 21:55:46 -0400 | [diff] [blame] | 75 | brk++; |
Nicolas Pitre | 6b9c42b | 2008-09-03 15:13:42 -0400 | [diff] [blame] | 76 | if (brk > len) { |
| 77 | brk = 0; |
| 78 | break; |
| 79 | } |
| 80 | if (b[brk-1] == '\n' || |
| 81 | b[brk-1] == '\r') |
Nicolas Pitre | ed1902e | 2007-10-16 21:55:46 -0400 | [diff] [blame] | 82 | break; |
| 83 | } |
Nicolas Pitre | ebe8fa7 | 2007-11-04 00:22:42 -0400 | [diff] [blame] | 84 | |
| 85 | /* |
| 86 | * Let's insert a suffix to clear the end |
Nicolas Pitre | 6b9c42b | 2008-09-03 15:13:42 -0400 | [diff] [blame] | 87 | * of the screen line if a line break was |
| 88 | * found. Also, if we don't skip the |
| 89 | * prefix, then a non-empty string must be |
| 90 | * present too. |
Nicolas Pitre | ebe8fa7 | 2007-11-04 00:22:42 -0400 | [diff] [blame] | 91 | */ |
Nicolas Pitre | 6b9c42b | 2008-09-03 15:13:42 -0400 | [diff] [blame] | 92 | if (brk > (skip_pf ? 0 : (pf+1 + 1))) { |
Johannes Sixt | 13e4760 | 2008-01-08 17:24:53 +0100 | [diff] [blame] | 93 | char save[FIX_SIZE]; |
Nicolas Pitre | 6b9c42b | 2008-09-03 15:13:42 -0400 | [diff] [blame] | 94 | memcpy(save, b + brk, sf); |
| 95 | b[brk + sf - 1] = b[brk - 1]; |
| 96 | memcpy(b + brk - 1, suffix, sf); |
Johannes Sixt | 34df8ab | 2009-03-10 22:54:17 +0100 | [diff] [blame] | 97 | fprintf(stderr, "%.*s", brk + sf, b); |
Nicolas Pitre | 6b9c42b | 2008-09-03 15:13:42 -0400 | [diff] [blame] | 98 | memcpy(b + brk, save, sf); |
| 99 | len -= brk; |
| 100 | } else { |
| 101 | int l = brk ? brk : len; |
Johannes Sixt | 34df8ab | 2009-03-10 22:54:17 +0100 | [diff] [blame] | 102 | fprintf(stderr, "%.*s", l, b); |
Nicolas Pitre | 6b9c42b | 2008-09-03 15:13:42 -0400 | [diff] [blame] | 103 | len -= l; |
| 104 | } |
Nicolas Pitre | ebe8fa7 | 2007-11-04 00:22:42 -0400 | [diff] [blame] | 105 | |
Nicolas Pitre | 6b9c42b | 2008-09-03 15:13:42 -0400 | [diff] [blame] | 106 | skip_pf = !brk; |
| 107 | memmove(buf + pf+1, b + brk, len); |
| 108 | } while (len); |
Junio C Hamano | 49a52b1 | 2006-09-10 01:06:33 -0700 | [diff] [blame] | 109 | continue; |
| 110 | case 1: |
Nicolas Pitre | ebe8fa7 | 2007-11-04 00:22:42 -0400 | [diff] [blame] | 111 | safe_write(out, buf + pf+1, len); |
Junio C Hamano | 49a52b1 | 2006-09-10 01:06:33 -0700 | [diff] [blame] | 112 | continue; |
| 113 | default: |
Johannes Sixt | 34df8ab | 2009-03-10 22:54:17 +0100 | [diff] [blame] | 114 | fprintf(stderr, "%s: protocol error: bad band #%d\n", |
| 115 | me, band); |
Junio C Hamano | 49a52b1 | 2006-09-10 01:06:33 -0700 | [diff] [blame] | 116 | return SIDEBAND_PROTOCOL_ERROR; |
| 117 | } |
| 118 | } |
| 119 | return 0; |
| 120 | } |
Junio C Hamano | 958c24b | 2006-09-10 03:20:24 -0700 | [diff] [blame] | 121 | |
| 122 | /* |
| 123 | * fd is connected to the remote side; send the sideband data |
| 124 | * over multiplexed packet stream. |
| 125 | */ |
| 126 | ssize_t send_sideband(int fd, int band, const char *data, ssize_t sz, int packet_max) |
| 127 | { |
| 128 | ssize_t ssz = sz; |
| 129 | const char *p = data; |
| 130 | |
| 131 | while (sz) { |
| 132 | unsigned n; |
| 133 | char hdr[5]; |
| 134 | |
| 135 | n = sz; |
| 136 | if (packet_max - 5 < n) |
| 137 | n = packet_max - 5; |
Shawn O. Pearce | de1a2fd | 2009-10-30 17:47:41 -0700 | [diff] [blame] | 138 | if (0 <= band) { |
| 139 | sprintf(hdr, "%04x", n + 5); |
| 140 | hdr[4] = band; |
| 141 | safe_write(fd, hdr, 5); |
| 142 | } else { |
| 143 | sprintf(hdr, "%04x", n + 4); |
| 144 | safe_write(fd, hdr, 4); |
| 145 | } |
Junio C Hamano | 958c24b | 2006-09-10 03:20:24 -0700 | [diff] [blame] | 146 | safe_write(fd, p, n); |
| 147 | p += n; |
| 148 | sz -= n; |
| 149 | } |
| 150 | return ssz; |
| 151 | } |