1251881Speter/* 2251881Speter * streams.c : stream encapsulation routines for the ra_svn protocol 3251881Speter * 4251881Speter * ==================================================================== 5251881Speter * Licensed to the Apache Software Foundation (ASF) under one 6251881Speter * or more contributor license agreements. See the NOTICE file 7251881Speter * distributed with this work for additional information 8251881Speter * regarding copyright ownership. The ASF licenses this file 9251881Speter * to you under the Apache License, Version 2.0 (the 10251881Speter * "License"); you may not use this file except in compliance 11251881Speter * with the License. You may obtain a copy of the License at 12251881Speter * 13251881Speter * http://www.apache.org/licenses/LICENSE-2.0 14251881Speter * 15251881Speter * Unless required by applicable law or agreed to in writing, 16251881Speter * software distributed under the License is distributed on an 17251881Speter * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 18251881Speter * KIND, either express or implied. See the License for the 19251881Speter * specific language governing permissions and limitations 20251881Speter * under the License. 21251881Speter * ==================================================================== 22251881Speter */ 23251881Speter 24251881Speter 25251881Speter 26251881Speter#include <apr_general.h> 27251881Speter#include <apr_network_io.h> 28251881Speter#include <apr_poll.h> 29251881Speter 30251881Speter#include "svn_types.h" 31251881Speter#include "svn_error.h" 32251881Speter#include "svn_pools.h" 33251881Speter#include "svn_io.h" 34251881Speter#include "svn_private_config.h" 35251881Speter 36289180Speter#include "private/svn_io_private.h" 37289180Speter 38251881Speter#include "ra_svn.h" 39251881Speter 40251881Speterstruct svn_ra_svn__stream_st { 41289180Speter svn_stream_t *in_stream; 42289180Speter svn_stream_t *out_stream; 43289180Speter void *timeout_baton; 44251881Speter ra_svn_timeout_fn_t timeout_fn; 45251881Speter}; 46251881Speter 47251881Spetertypedef struct sock_baton_t { 48251881Speter apr_socket_t *sock; 49251881Speter apr_pool_t *pool; 50251881Speter} sock_baton_t; 51251881Speter 52251881Speter 53251881Speter/* Returns TRUE if PFD has pending data, FALSE otherwise. */ 54251881Speterstatic svn_boolean_t pending(apr_pollfd_t *pfd, apr_pool_t *pool) 55251881Speter{ 56251881Speter apr_status_t status; 57251881Speter int n; 58251881Speter 59251881Speter pfd->p = pool; 60251881Speter pfd->reqevents = APR_POLLIN; 61251881Speter status = apr_poll(pfd, 1, &n, 0); 62251881Speter return (status == APR_SUCCESS && n); 63251881Speter} 64251881Speter 65251881Speter/* Functions to implement a file backed svn_ra_svn__stream_t. */ 66251881Speter 67251881Speter/* Implements ra_svn_timeout_fn_t */ 68251881Speterstatic void 69251881Speterfile_timeout_cb(void *baton, apr_interval_time_t interval) 70251881Speter{ 71289180Speter apr_file_t *f = baton; 72251881Speter 73289180Speter if (f) 74289180Speter apr_file_pipe_timeout_set(f, interval); 75251881Speter} 76251881Speter 77251881Spetersvn_ra_svn__stream_t * 78289180Spetersvn_ra_svn__stream_from_streams(svn_stream_t *in_stream, 79289180Speter svn_stream_t *out_stream, 80289180Speter apr_pool_t *pool) 81251881Speter{ 82289180Speter apr_file_t *file; 83251881Speter 84289180Speter /* If out_stream is backed by an apr_file (e.g. an PIPE) we 85289180Speter provide a working callback, otherwise the callback ignores 86289180Speter the timeout. 87251881Speter 88289180Speter The callback is used to make the write non-blocking on 89289180Speter some error scenarios. ### This (legacy) usage 90289180Speter breaks the stream promise */ 91289180Speter file = svn_stream__aprfile(out_stream); 92289180Speter 93289180Speter return svn_ra_svn__stream_create(in_stream, out_stream, 94289180Speter file, file_timeout_cb, 95251881Speter pool); 96251881Speter} 97251881Speter 98251881Speter/* Functions to implement a socket backed svn_ra_svn__stream_t. */ 99251881Speter 100251881Speter/* Implements svn_read_fn_t */ 101251881Speterstatic svn_error_t * 102251881Spetersock_read_cb(void *baton, char *buffer, apr_size_t *len) 103251881Speter{ 104251881Speter sock_baton_t *b = baton; 105251881Speter apr_status_t status; 106251881Speter apr_interval_time_t interval; 107251881Speter 108251881Speter status = apr_socket_timeout_get(b->sock, &interval); 109251881Speter if (status) 110251881Speter return svn_error_wrap_apr(status, _("Can't get socket timeout")); 111251881Speter 112251881Speter /* Always block on read. 113251881Speter * During pipelining, we set the timeout to 0 for some write 114251881Speter * operations so that we can try them without blocking. If APR had 115251881Speter * separate timeouts for read and write, we would only set the 116251881Speter * write timeout, but it doesn't. So here, we revert back to blocking. 117251881Speter */ 118251881Speter apr_socket_timeout_set(b->sock, -1); 119251881Speter status = apr_socket_recv(b->sock, buffer, len); 120251881Speter apr_socket_timeout_set(b->sock, interval); 121251881Speter 122251881Speter if (status && !APR_STATUS_IS_EOF(status)) 123251881Speter return svn_error_wrap_apr(status, _("Can't read from connection")); 124251881Speter return SVN_NO_ERROR; 125251881Speter} 126251881Speter 127251881Speter/* Implements svn_write_fn_t */ 128251881Speterstatic svn_error_t * 129251881Spetersock_write_cb(void *baton, const char *buffer, apr_size_t *len) 130251881Speter{ 131251881Speter sock_baton_t *b = baton; 132251881Speter apr_status_t status = apr_socket_send(b->sock, buffer, len); 133251881Speter if (status) 134251881Speter return svn_error_wrap_apr(status, _("Can't write to connection")); 135251881Speter return SVN_NO_ERROR; 136251881Speter} 137251881Speter 138251881Speter/* Implements ra_svn_timeout_fn_t */ 139251881Speterstatic void 140251881Spetersock_timeout_cb(void *baton, apr_interval_time_t interval) 141251881Speter{ 142251881Speter sock_baton_t *b = baton; 143251881Speter apr_socket_timeout_set(b->sock, interval); 144251881Speter} 145251881Speter 146289180Speter/* Implements svn_stream_data_available_fn_t */ 147289180Speterstatic svn_error_t * 148289180Spetersock_pending_cb(void *baton, 149289180Speter svn_boolean_t *data_available) 150251881Speter{ 151251881Speter sock_baton_t *b = baton; 152251881Speter apr_pollfd_t pfd; 153251881Speter 154251881Speter pfd.desc_type = APR_POLL_SOCKET; 155251881Speter pfd.desc.s = b->sock; 156251881Speter 157289180Speter *data_available = pending(&pfd, b->pool); 158289180Speter 159289180Speter svn_pool_clear(b->pool); 160289180Speter 161289180Speter return SVN_NO_ERROR; 162251881Speter} 163251881Speter 164251881Spetersvn_ra_svn__stream_t * 165251881Spetersvn_ra_svn__stream_from_sock(apr_socket_t *sock, 166289180Speter apr_pool_t *result_pool) 167251881Speter{ 168289180Speter sock_baton_t *b = apr_palloc(result_pool, sizeof(*b)); 169289180Speter svn_stream_t *sock_stream; 170251881Speter 171251881Speter b->sock = sock; 172289180Speter b->pool = svn_pool_create(result_pool); 173251881Speter 174289180Speter sock_stream = svn_stream_create(b, result_pool); 175289180Speter 176289180Speter svn_stream_set_read2(sock_stream, sock_read_cb, NULL /* use default */); 177289180Speter svn_stream_set_write(sock_stream, sock_write_cb); 178289180Speter svn_stream_set_data_available(sock_stream, sock_pending_cb); 179289180Speter 180289180Speter return svn_ra_svn__stream_create(sock_stream, sock_stream, 181289180Speter b, sock_timeout_cb, result_pool); 182251881Speter} 183251881Speter 184251881Spetersvn_ra_svn__stream_t * 185289180Spetersvn_ra_svn__stream_create(svn_stream_t *in_stream, 186289180Speter svn_stream_t *out_stream, 187289180Speter void *timeout_baton, 188251881Speter ra_svn_timeout_fn_t timeout_cb, 189251881Speter apr_pool_t *pool) 190251881Speter{ 191251881Speter svn_ra_svn__stream_t *s = apr_palloc(pool, sizeof(*s)); 192289180Speter s->in_stream = in_stream; 193289180Speter s->out_stream = out_stream; 194289180Speter s->timeout_baton = timeout_baton; 195251881Speter s->timeout_fn = timeout_cb; 196251881Speter return s; 197251881Speter} 198251881Speter 199251881Spetersvn_error_t * 200251881Spetersvn_ra_svn__stream_write(svn_ra_svn__stream_t *stream, 201251881Speter const char *data, apr_size_t *len) 202251881Speter{ 203289180Speter return svn_error_trace(svn_stream_write(stream->out_stream, data, len)); 204251881Speter} 205251881Speter 206251881Spetersvn_error_t * 207251881Spetersvn_ra_svn__stream_read(svn_ra_svn__stream_t *stream, char *data, 208251881Speter apr_size_t *len) 209251881Speter{ 210289180Speter SVN_ERR(svn_stream_read2(stream->in_stream, data, len)); 211289180Speter 212289180Speter if (*len == 0) 213289180Speter return svn_error_create(SVN_ERR_RA_SVN_CONNECTION_CLOSED, NULL, NULL); 214289180Speter 215289180Speter return SVN_NO_ERROR; 216251881Speter} 217251881Speter 218251881Spetervoid 219251881Spetersvn_ra_svn__stream_timeout(svn_ra_svn__stream_t *stream, 220251881Speter apr_interval_time_t interval) 221251881Speter{ 222289180Speter stream->timeout_fn(stream->timeout_baton, interval); 223251881Speter} 224251881Speter 225289180Spetersvn_error_t * 226289180Spetersvn_ra_svn__stream_data_available(svn_ra_svn__stream_t *stream, 227289180Speter svn_boolean_t *data_available) 228251881Speter{ 229289180Speter return svn_error_trace( 230289180Speter svn_stream_data_available(stream->in_stream, 231289180Speter data_available)); 232251881Speter} 233