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