1 /*-
2  * Copyright (c) 2003-2005 MAEKAWA Masahide <maekawa@cvsync.org>
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  * 3. Neither the name of the author nor the names of its contributors
14  *    may be used to endorse or promote products derived from this software
15  *    without specific prior written permission.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
21  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27  * SUCH DAMAGE.
28  */
29 
30 #include <sys/types.h>
31 #include <sys/socket.h>
32 
33 #include <stdlib.h>
34 
35 #include <errno.h>
36 #include <limits.h>
37 #include <pthread.h>
38 #include <string.h>
39 
40 #include <zlib.h>
41 
42 #include "compat_stdbool.h"
43 #include "compat_stdint.h"
44 #include "compat_inttypes.h"
45 #include "compat_limits.h"
46 #include "basedef.h"
47 
48 #include "cvsync.h"
49 #include "logmsg.h"
50 #include "mux.h"
51 #include "mux_zlib.h"
52 #include "network.h"
53 
54 bool
mux_init_zlib(struct mux * mx,int level)55 mux_init_zlib(struct mux *mx, int level)
56 {
57 	struct mux_stream_zlib *stream;
58 
59 	if ((stream = malloc(sizeof(*stream))) == NULL) {
60 		logmsg_err("Mux Error: %s", strerror(errno));
61 		return (false);
62 	}
63 	stream->ms_zbufsize_in = sizeof(stream->ms_zbuffer_in);
64 	stream->ms_zbufsize_out = sizeof(stream->ms_zbuffer_out);
65 
66 	stream->ms_zstream_in.zalloc = Z_NULL;
67 	stream->ms_zstream_in.zfree = Z_NULL;
68 	stream->ms_zstream_in.opaque = Z_NULL;
69 	if (inflateInit(&stream->ms_zstream_in) != Z_OK) {
70 		logmsg_err("Mux Error: INFLATE init: %s",
71 			   stream->ms_zstream_in.msg);
72 		free(stream);
73 		return (false);
74 	}
75 
76 	stream->ms_zstream_out.zalloc = Z_NULL;
77 	stream->ms_zstream_out.zfree = Z_NULL;
78 	stream->ms_zstream_out.opaque = Z_NULL;
79 	if (deflateInit(&stream->ms_zstream_out, level) != Z_OK) {
80 		logmsg_err("Mux Error: DEFLATE init: %s",
81 			   stream->ms_zstream_out.msg);
82 		inflateEnd(&stream->ms_zstream_in);
83 		free(stream);
84 		return (false);
85 	}
86 	stream->ms_zstream_out.next_out = stream->ms_zbuffer_out;
87 	stream->ms_zstream_out.avail_out = stream->ms_zbufsize_out;
88 
89 	mx->mx_stream = stream;
90 
91 	return (true);
92 }
93 
94 void
mux_destroy_zlib(struct mux * mx)95 mux_destroy_zlib(struct mux *mx)
96 {
97 	struct mux_stream_zlib *stream = mx->mx_stream;
98 
99 	inflateEnd(&stream->ms_zstream_in);
100 	deflateEnd(&stream->ms_zstream_out);
101 	free(stream);
102 }
103 
104 bool
mux_send_zlib(struct mux * mx,uint8_t chnum,const void * buffer,size_t bufsize)105 mux_send_zlib(struct mux *mx, uint8_t chnum, const void *buffer, size_t bufsize)
106 {
107 	struct muxbuf *mxb = &mx->mx_buffer[MUX_OUT][chnum];
108 	struct mux_stream_zlib *stream = mx->mx_stream;
109 	z_stream *z = &stream->ms_zstream_out;
110 	uint8_t cmd[MUX_CMDLEN_DATA];
111 
112 	if (mxb->mxb_length > 0) {
113 		z->next_in = mxb->mxb_buffer;
114 		z->avail_in = mxb->mxb_length;
115 		if (deflate(z, Z_NO_FLUSH) != Z_OK) {
116 			logmsg_err("Mux(SEND) Error: DEFLATE: %s", z->msg);
117 			return (false);
118 		}
119 	}
120 	z->next_in = (void *)(unsigned long)buffer;
121 	z->avail_in = bufsize;
122 	if (deflate(z, Z_FINISH) != Z_STREAM_END) {
123 		logmsg_err("Mux(SEND) Error: DEFLATE: %s", z->msg);
124 		return (false);
125 	}
126 	if (z->total_out > mxb->mxb_mss) {
127 		logmsg_err("Mux(SEND) Error: DEFLATE: %u > %u(mss)",
128 			   z->total_out, mxb->mxb_mss);
129 		return (false);
130 	}
131 
132 	logmsg_debug(DEBUG_ZLIB, "DEFLATE: %u => %u",
133 		     mxb->mxb_length + bufsize, z->total_out);
134 
135 	cmd[0] = MUX_CMD_DATA;
136 	cmd[1] = chnum;
137 	SetWord(&cmd[2], z->total_out);
138 
139 	if (!sock_send(mx->mx_socket, cmd, MUX_CMDLEN_DATA)) {
140 		logmsg_err("Mux(SEND) Error: send");
141 		return (false);
142 	}
143 	if (!sock_send(mx->mx_socket, stream->ms_zbuffer_out,
144 		       (size_t)z->total_out)) {
145 		logmsg_err("Mux(SEND) Error: send");
146 		return (false);
147 	}
148 	mx->mx_xfer_out += mxb->mxb_length + bufsize;
149 
150 	if (deflateReset(z) != Z_OK) {
151 		logmsg_err("Mux(SEND) Error: DEFLATE: %s", z->msg);
152 		return (false);
153 	}
154 	z->next_out = stream->ms_zbuffer_out;
155 	z->avail_out = stream->ms_zbufsize_out;
156 	z->total_out = 0;
157 
158 	return (true);
159 }
160 
161 bool
mux_flush_zlib(struct mux * mx,uint8_t chnum)162 mux_flush_zlib(struct mux *mx, uint8_t chnum)
163 {
164 	struct muxbuf *mxb = &mx->mx_buffer[MUX_OUT][chnum];
165 	struct mux_stream_zlib *stream = mx->mx_stream;
166 	z_stream *z = &stream->ms_zstream_out;
167 	uint8_t cmd[MUX_CMDLEN_DATA];
168 
169 	z->next_in = mxb->mxb_buffer;
170 	z->avail_in = mxb->mxb_length;
171 	if (deflate(z, Z_FINISH) != Z_STREAM_END) {
172 		logmsg_err("Mux(FLUSH) Error: DEFLATE: %s", z->msg);
173 		return (false);
174 	}
175 	if (z->total_out > mxb->mxb_mss) {
176 		logmsg_err("Mux(FLUSH) Error: DEFLATE: %u > %u(mss)",
177 			   z->total_out, mxb->mxb_mss);
178 		return (false);
179 	}
180 
181 	logmsg_debug(DEBUG_ZLIB, "DEFLATE: %u => %u", mxb->mxb_length,
182 		     z->total_out);
183 
184 	cmd[0] = MUX_CMD_DATA;
185 	cmd[1] = chnum;
186 	SetWord(&cmd[2], z->total_out);
187 
188 	if (!sock_send(mx->mx_socket, cmd, MUX_CMDLEN_DATA)) {
189 		logmsg_err("Mux(FLUSH) Error: send");
190 		return (false);
191 	}
192 	if (!sock_send(mx->mx_socket, stream->ms_zbuffer_out,
193 		       (size_t)z->total_out)) {
194 		logmsg_err("Mux(FLUSH) Error: send");
195 		return (false);
196 	}
197 	mx->mx_xfer_out += mxb->mxb_length;
198 
199 	if (deflateReset(z) != Z_OK) {
200 		logmsg_err("Mux(FLUSH) Error: DEFLATE: %s", z->msg);
201 		return (false);
202 	}
203 	z->next_out = stream->ms_zbuffer_out;
204 	z->avail_out = stream->ms_zbufsize_out;
205 	z->total_out = 0;
206 
207 	return (true);
208 }
209