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 36251881Speter#include "ra_svn.h" 37251881Speter 38251881Speterstruct svn_ra_svn__stream_st { 39251881Speter svn_stream_t *stream; 40251881Speter void *baton; 41251881Speter ra_svn_pending_fn_t pending_fn; 42251881Speter ra_svn_timeout_fn_t timeout_fn; 43251881Speter}; 44251881Speter 45251881Spetertypedef struct sock_baton_t { 46251881Speter apr_socket_t *sock; 47251881Speter apr_pool_t *pool; 48251881Speter} sock_baton_t; 49251881Speter 50251881Spetertypedef struct file_baton_t { 51251881Speter apr_file_t *in_file; 52251881Speter apr_file_t *out_file; 53251881Speter apr_pool_t *pool; 54251881Speter} file_baton_t; 55251881Speter 56251881Speter/* Returns TRUE if PFD has pending data, FALSE otherwise. */ 57251881Speterstatic svn_boolean_t pending(apr_pollfd_t *pfd, apr_pool_t *pool) 58251881Speter{ 59251881Speter apr_status_t status; 60251881Speter int n; 61251881Speter 62251881Speter pfd->p = pool; 63251881Speter pfd->reqevents = APR_POLLIN; 64251881Speter status = apr_poll(pfd, 1, &n, 0); 65251881Speter return (status == APR_SUCCESS && n); 66251881Speter} 67251881Speter 68251881Speter/* Functions to implement a file backed svn_ra_svn__stream_t. */ 69251881Speter 70251881Speter/* Implements svn_read_fn_t */ 71251881Speterstatic svn_error_t * 72251881Speterfile_read_cb(void *baton, char *buffer, apr_size_t *len) 73251881Speter{ 74251881Speter file_baton_t *b = baton; 75251881Speter apr_status_t status = apr_file_read(b->in_file, buffer, len); 76251881Speter 77251881Speter if (status && !APR_STATUS_IS_EOF(status)) 78251881Speter return svn_error_wrap_apr(status, _("Can't read from connection")); 79251881Speter if (*len == 0) 80251881Speter return svn_error_create(SVN_ERR_RA_SVN_CONNECTION_CLOSED, NULL, NULL); 81251881Speter return SVN_NO_ERROR; 82251881Speter} 83251881Speter 84251881Speter/* Implements svn_write_fn_t */ 85251881Speterstatic svn_error_t * 86251881Speterfile_write_cb(void *baton, const char *buffer, apr_size_t *len) 87251881Speter{ 88251881Speter file_baton_t *b = baton; 89251881Speter apr_status_t status = apr_file_write(b->out_file, buffer, len); 90251881Speter if (status) 91251881Speter return svn_error_wrap_apr(status, _("Can't write to connection")); 92251881Speter return SVN_NO_ERROR; 93251881Speter} 94251881Speter 95251881Speter/* Implements ra_svn_timeout_fn_t */ 96251881Speterstatic void 97251881Speterfile_timeout_cb(void *baton, apr_interval_time_t interval) 98251881Speter{ 99251881Speter file_baton_t *b = baton; 100251881Speter apr_file_pipe_timeout_set(b->out_file, interval); 101251881Speter} 102251881Speter 103251881Speter/* Implements ra_svn_pending_fn_t */ 104251881Speterstatic svn_boolean_t 105251881Speterfile_pending_cb(void *baton) 106251881Speter{ 107251881Speter file_baton_t *b = baton; 108251881Speter apr_pollfd_t pfd; 109251881Speter 110251881Speter pfd.desc_type = APR_POLL_FILE; 111251881Speter pfd.desc.f = b->in_file; 112251881Speter 113251881Speter return pending(&pfd, b->pool); 114251881Speter} 115251881Speter 116251881Spetersvn_ra_svn__stream_t * 117251881Spetersvn_ra_svn__stream_from_files(apr_file_t *in_file, 118251881Speter apr_file_t *out_file, 119251881Speter apr_pool_t *pool) 120251881Speter{ 121251881Speter file_baton_t *b = apr_palloc(pool, sizeof(*b)); 122251881Speter 123251881Speter b->in_file = in_file; 124251881Speter b->out_file = out_file; 125251881Speter b->pool = pool; 126251881Speter 127251881Speter return svn_ra_svn__stream_create(b, file_read_cb, file_write_cb, 128251881Speter file_timeout_cb, file_pending_cb, 129251881Speter pool); 130251881Speter} 131251881Speter 132251881Speter/* Functions to implement a socket backed svn_ra_svn__stream_t. */ 133251881Speter 134251881Speter/* Implements svn_read_fn_t */ 135251881Speterstatic svn_error_t * 136251881Spetersock_read_cb(void *baton, char *buffer, apr_size_t *len) 137251881Speter{ 138251881Speter sock_baton_t *b = baton; 139251881Speter apr_status_t status; 140251881Speter apr_interval_time_t interval; 141251881Speter 142251881Speter status = apr_socket_timeout_get(b->sock, &interval); 143251881Speter if (status) 144251881Speter return svn_error_wrap_apr(status, _("Can't get socket timeout")); 145251881Speter 146251881Speter /* Always block on read. 147251881Speter * During pipelining, we set the timeout to 0 for some write 148251881Speter * operations so that we can try them without blocking. If APR had 149251881Speter * separate timeouts for read and write, we would only set the 150251881Speter * write timeout, but it doesn't. So here, we revert back to blocking. 151251881Speter */ 152251881Speter apr_socket_timeout_set(b->sock, -1); 153251881Speter status = apr_socket_recv(b->sock, buffer, len); 154251881Speter apr_socket_timeout_set(b->sock, interval); 155251881Speter 156251881Speter if (status && !APR_STATUS_IS_EOF(status)) 157251881Speter return svn_error_wrap_apr(status, _("Can't read from connection")); 158251881Speter if (*len == 0) 159251881Speter return svn_error_create(SVN_ERR_RA_SVN_CONNECTION_CLOSED, NULL, NULL); 160251881Speter return SVN_NO_ERROR; 161251881Speter} 162251881Speter 163251881Speter/* Implements svn_write_fn_t */ 164251881Speterstatic svn_error_t * 165251881Spetersock_write_cb(void *baton, const char *buffer, apr_size_t *len) 166251881Speter{ 167251881Speter sock_baton_t *b = baton; 168251881Speter apr_status_t status = apr_socket_send(b->sock, buffer, len); 169251881Speter if (status) 170251881Speter return svn_error_wrap_apr(status, _("Can't write to connection")); 171251881Speter return SVN_NO_ERROR; 172251881Speter} 173251881Speter 174251881Speter/* Implements ra_svn_timeout_fn_t */ 175251881Speterstatic void 176251881Spetersock_timeout_cb(void *baton, apr_interval_time_t interval) 177251881Speter{ 178251881Speter sock_baton_t *b = baton; 179251881Speter apr_socket_timeout_set(b->sock, interval); 180251881Speter} 181251881Speter 182251881Speter/* Implements ra_svn_pending_fn_t */ 183251881Speterstatic svn_boolean_t 184251881Spetersock_pending_cb(void *baton) 185251881Speter{ 186251881Speter sock_baton_t *b = baton; 187251881Speter apr_pollfd_t pfd; 188251881Speter 189251881Speter pfd.desc_type = APR_POLL_SOCKET; 190251881Speter pfd.desc.s = b->sock; 191251881Speter 192251881Speter return pending(&pfd, b->pool); 193251881Speter} 194251881Speter 195251881Spetersvn_ra_svn__stream_t * 196251881Spetersvn_ra_svn__stream_from_sock(apr_socket_t *sock, 197251881Speter apr_pool_t *pool) 198251881Speter{ 199251881Speter sock_baton_t *b = apr_palloc(pool, sizeof(*b)); 200251881Speter 201251881Speter b->sock = sock; 202251881Speter b->pool = pool; 203251881Speter 204251881Speter return svn_ra_svn__stream_create(b, sock_read_cb, sock_write_cb, 205251881Speter sock_timeout_cb, sock_pending_cb, 206251881Speter pool); 207251881Speter} 208251881Speter 209251881Spetersvn_ra_svn__stream_t * 210251881Spetersvn_ra_svn__stream_create(void *baton, 211251881Speter svn_read_fn_t read_cb, 212251881Speter svn_write_fn_t write_cb, 213251881Speter ra_svn_timeout_fn_t timeout_cb, 214251881Speter ra_svn_pending_fn_t pending_cb, 215251881Speter apr_pool_t *pool) 216251881Speter{ 217251881Speter svn_ra_svn__stream_t *s = apr_palloc(pool, sizeof(*s)); 218251881Speter s->stream = svn_stream_empty(pool); 219251881Speter svn_stream_set_baton(s->stream, baton); 220251881Speter if (read_cb) 221251881Speter svn_stream_set_read(s->stream, read_cb); 222251881Speter if (write_cb) 223251881Speter svn_stream_set_write(s->stream, write_cb); 224251881Speter s->baton = baton; 225251881Speter s->timeout_fn = timeout_cb; 226251881Speter s->pending_fn = pending_cb; 227251881Speter return s; 228251881Speter} 229251881Speter 230251881Spetersvn_error_t * 231251881Spetersvn_ra_svn__stream_write(svn_ra_svn__stream_t *stream, 232251881Speter const char *data, apr_size_t *len) 233251881Speter{ 234251881Speter return svn_stream_write(stream->stream, data, len); 235251881Speter} 236251881Speter 237251881Spetersvn_error_t * 238251881Spetersvn_ra_svn__stream_read(svn_ra_svn__stream_t *stream, char *data, 239251881Speter apr_size_t *len) 240251881Speter{ 241251881Speter return svn_stream_read(stream->stream, data, len); 242251881Speter} 243251881Speter 244251881Spetervoid 245251881Spetersvn_ra_svn__stream_timeout(svn_ra_svn__stream_t *stream, 246251881Speter apr_interval_time_t interval) 247251881Speter{ 248251881Speter stream->timeout_fn(stream->baton, interval); 249251881Speter} 250251881Speter 251251881Spetersvn_boolean_t 252251881Spetersvn_ra_svn__stream_pending(svn_ra_svn__stream_t *stream) 253251881Speter{ 254251881Speter return stream->pending_fn(stream->baton); 255251881Speter} 256