1/*
2	logging.c
3
4	Message logging plugin and stat collector for webserver.
5
6	Register the plugin with:
7		soap_register_plugin(soap, logging);
8
9	Change logging destinations:
10		soap_set_logging_inbound(struct soap*, FILE*);
11		soap_set_logging_outbound(struct soap*, FILE*);
12
13	Obtain stats (sent and recv octet count, independent of log dest):
14		soap_get_logging_stats(soap, size_t *sent, size_t *recv);
15
16gSOAP XML Web services tools
17Copyright (C) 2000-2008, Robert van Engelen, Genivia Inc., All Rights Reserved.
18This part of the software is released under one of the following licenses:
19GPL, the gSOAP public license, or Genivia's license for commercial use.
20--------------------------------------------------------------------------------
21gSOAP public license.
22
23The contents of this file are subject to the gSOAP Public License Version 1.3
24(the "License"); you may not use this file except in compliance with the
25License. You may obtain a copy of the License at
26http://www.cs.fsu.edu/~engelen/soaplicense.html
27Software distributed under the License is distributed on an "AS IS" basis,
28WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
29for the specific language governing rights and limitations under the License.
30
31The Initial Developer of the Original Code is Robert A. van Engelen.
32Copyright (C) 2000-2008, Robert van Engelen, Genivia Inc., All Rights Reserved.
33--------------------------------------------------------------------------------
34GPL license.
35
36This program is free software; you can redistribute it and/or modify it under
37the terms of the GNU General Public License as published by the Free Software
38Foundation; either version 2 of the License, or (at your option) any later
39version.
40
41This program is distributed in the hope that it will be useful, but WITHOUT ANY
42WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
43PARTICULAR PURPOSE. See the GNU General Public License for more details.
44
45You should have received a copy of the GNU General Public License along with
46this program; if not, write to the Free Software Foundation, Inc., 59 Temple
47Place, Suite 330, Boston, MA 02111-1307 USA
48
49Author contact information:
50engelen@genivia.com / engelen@acm.org
51
52This program is released under the GPL with the additional exemption that
53compiling, linking, and/or using OpenSSL is allowed.
54--------------------------------------------------------------------------------
55A commercial use license is available from Genivia, Inc., contact@genivia.com
56--------------------------------------------------------------------------------
57*/
58
59#include "logging.h"
60
61#ifdef __cplusplus
62extern "C" {
63#endif
64
65const char logging_id[] = LOGGING_ID;
66
67static int logging_init(struct soap *soap, struct logging_data *data);
68static void logging_delete(struct soap *soap, struct soap_plugin *p);
69static int logging_send(struct soap *soap, const char *buf, size_t len);
70static size_t logging_recv(struct soap *soap, char *buf, size_t len);
71
72/* plugin registry function, invoked by soap_register_plugin */
73int logging(struct soap *soap, struct soap_plugin *p, void *arg)
74{ p->id = logging_id;
75  /* create local plugin data */
76  p->data = (void*)SOAP_MALLOC(soap, sizeof(struct logging_data));
77  /* register the destructor */
78  p->fdelete = logging_delete;
79  /* if OK then initialize */
80  if (p->data)
81  { if (logging_init(soap, (struct logging_data*)p->data))
82    { SOAP_FREE(soap, p->data); /* error: could not init */
83      return SOAP_EOM; /* return error */
84    }
85  }
86  return SOAP_OK;
87}
88
89/* set inbound logging FD, NULL to disable */
90void soap_set_logging_inbound(struct soap *soap, FILE *fd)
91{ struct logging_data *data = (struct logging_data*)soap_lookup_plugin(soap, logging_id);
92  if (data)
93    data->inbound = fd;
94}
95
96/* set outbound logging FD, NULL to disable */
97void soap_set_logging_outbound(struct soap *soap, FILE *fd)
98{ struct logging_data *data = (struct logging_data*)soap_lookup_plugin(soap, logging_id);
99  if (data)
100    data->outbound = fd;
101}
102
103/* get logging sent and recv octet counts */
104void soap_get_logging_stats(struct soap *soap, size_t *sent, size_t *recv)
105{ struct logging_data *data = (struct logging_data*)soap_lookup_plugin(soap, logging_id);
106  if (data)
107  { *sent = data->stat_sent;
108    *recv = data->stat_recv;
109  }
110}
111
112/* used by plugin registry function */
113static int logging_init(struct soap *soap, struct logging_data *data)
114{ data->inbound = NULL;
115  data->outbound = NULL;
116  data->stat_sent = 0;
117  data->stat_recv = 0;
118  data->fsend = soap->fsend; /* save old recv callback */
119  data->frecv = soap->frecv; /* save old send callback */
120  soap->fsend = logging_send; /* replace send callback with ours */
121  soap->frecv = logging_recv; /* replace recv callback with ours */
122  return SOAP_OK;
123}
124
125static void logging_delete(struct soap *soap, struct soap_plugin *p)
126{
127  /* free allocated plugin data. If fcopy() is not set, then this function is
128     not called for all copies of the plugin created with soap_copy(). In this
129     example, the fcopy() callback is omitted and the plugin data is shared by
130     the soap copies created with soap_copy() */
131  SOAP_FREE(soap, p->data);
132}
133
134static size_t logging_recv(struct soap *soap, char *buf, size_t len)
135{ struct logging_data *data = (struct logging_data*)soap_lookup_plugin(soap, logging_id);
136  size_t res;
137  /* get data from old recv callback */
138  res = data->frecv(soap, buf, len);
139  /* update should be in mutex, but we don't mind some inaccuracy in stats */
140  data->stat_recv += res;
141  if (data->inbound)
142    fwrite(buf, res, 1, data->inbound);
143  return res;
144}
145
146static int logging_send(struct soap *soap, const char *buf, size_t len)
147{ struct logging_data *data = (struct logging_data*)soap_lookup_plugin(soap, logging_id);
148  /* update should be in mutex, but we don't mind some inaccuracy in stats */
149  data->stat_sent += len;
150  if (data->outbound)
151    fwrite(buf, len, 1, data->outbound);
152  return data->fsend(soap, buf, len); /* pass data on to old send callback */
153}
154
155#ifdef __cplusplus
156}
157#endif
158
159