roaming_common.c revision 197670
1/* $OpenBSD: roaming_common.c,v 1.5 2009/06/27 09:32:43 andreas Exp $ */ 2/* 3 * Copyright (c) 2004-2009 AppGate Network Security AB 4 * 5 * Permission to use, copy, modify, and distribute this software for any 6 * purpose with or without fee is hereby granted, provided that the above 7 * copyright notice and this permission notice appear in all copies. 8 * 9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 12 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 15 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16 */ 17 18#include "includes.h" 19 20#include <sys/types.h> 21#include <sys/socket.h> 22#include <sys/uio.h> 23 24#include <errno.h> 25#ifdef HAVE_INTTYPES_H 26#include <inttypes.h> 27#endif 28#include <stdarg.h> 29#include <string.h> 30#include <unistd.h> 31 32#include "atomicio.h" 33#include "log.h" 34#include "packet.h" 35#include "xmalloc.h" 36#include "cipher.h" 37#include "buffer.h" 38#include "roaming.h" 39 40static size_t out_buf_size = 0; 41static char *out_buf = NULL; 42static size_t out_start; 43static size_t out_last; 44 45static u_int64_t write_bytes = 0; 46static u_int64_t read_bytes = 0; 47 48int roaming_enabled = 0; 49int resume_in_progress = 0; 50 51int 52get_snd_buf_size() 53{ 54 int fd = packet_get_connection_out(); 55 int optval, optvallen; 56 57 optvallen = sizeof(optval); 58 if (getsockopt(fd, SOL_SOCKET, SO_SNDBUF, &optval, &optvallen) != 0) 59 optval = DEFAULT_ROAMBUF; 60 return optval; 61} 62 63int 64get_recv_buf_size() 65{ 66 int fd = packet_get_connection_in(); 67 int optval, optvallen; 68 69 optvallen = sizeof(optval); 70 if (getsockopt(fd, SOL_SOCKET, SO_RCVBUF, &optval, &optvallen) != 0) 71 optval = DEFAULT_ROAMBUF; 72 return optval; 73} 74 75void 76set_out_buffer_size(size_t size) 77{ 78 /* 79 * The buffer size can only be set once and the buffer will live 80 * as long as the session lives. 81 */ 82 if (out_buf == NULL) { 83 out_buf_size = size; 84 out_buf = xmalloc(size); 85 out_start = 0; 86 out_last = 0; 87 } 88} 89 90u_int64_t 91get_recv_bytes(void) 92{ 93 return read_bytes; 94} 95 96void 97add_recv_bytes(u_int64_t num) 98{ 99 read_bytes += num; 100} 101 102u_int64_t 103get_sent_bytes(void) 104{ 105 return write_bytes; 106} 107 108void 109roam_set_bytes(u_int64_t sent, u_int64_t recvd) 110{ 111 read_bytes = recvd; 112 write_bytes = sent; 113} 114 115static void 116buf_append(const char *buf, size_t count) 117{ 118 if (count > out_buf_size) { 119 buf += count - out_buf_size; 120 count = out_buf_size; 121 } 122 if (count < out_buf_size - out_last) { 123 memcpy(out_buf + out_last, buf, count); 124 if (out_start > out_last) 125 out_start += count; 126 out_last += count; 127 } else { 128 /* data will wrap */ 129 size_t chunk = out_buf_size - out_last; 130 memcpy(out_buf + out_last, buf, chunk); 131 memcpy(out_buf, buf + chunk, count - chunk); 132 out_last = count - chunk; 133 out_start = out_last + 1; 134 } 135} 136 137ssize_t 138roaming_write(int fd, const void *buf, size_t count, int *cont) 139{ 140 ssize_t ret; 141 142 ret = write(fd, buf, count); 143 if (ret > 0 && !resume_in_progress) { 144 write_bytes += ret; 145 if (out_buf_size > 0) 146 buf_append(buf, ret); 147 } 148 debug3("Wrote %ld bytes for a total of %llu", (long)ret, 149 (unsigned long long)write_bytes); 150 return ret; 151} 152 153ssize_t 154roaming_read(int fd, void *buf, size_t count, int *cont) 155{ 156 ssize_t ret = read(fd, buf, count); 157 if (ret > 0) { 158 if (!resume_in_progress) { 159 read_bytes += ret; 160 } 161 } 162 return ret; 163} 164 165size_t 166roaming_atomicio(ssize_t(*f)(int, void*, size_t), int fd, void *buf, 167 size_t count) 168{ 169 size_t ret = atomicio(f, fd, buf, count); 170 171 if (f == vwrite && ret > 0 && !resume_in_progress) { 172 write_bytes += ret; 173 } else if (f == read && ret > 0 && !resume_in_progress) { 174 read_bytes += ret; 175 } 176 return ret; 177} 178 179void 180resend_bytes(int fd, u_int64_t *offset) 181{ 182 size_t available, needed; 183 184 if (out_start < out_last) 185 available = out_last - out_start; 186 else 187 available = out_buf_size; 188 needed = write_bytes - *offset; 189 debug3("resend_bytes: resend %lu bytes from %llu", 190 (unsigned long)needed, (unsigned long long)*offset); 191 if (needed > available) 192 fatal("Needed to resend more data than in the cache"); 193 if (out_last < needed) { 194 int chunkend = needed - out_last; 195 atomicio(vwrite, fd, out_buf + out_buf_size - chunkend, 196 chunkend); 197 atomicio(vwrite, fd, out_buf, out_last); 198 } else { 199 atomicio(vwrite, fd, out_buf + (out_last - needed), needed); 200 } 201} 202