soap-nudp.c

Go to the documentation of this file.
00001 /******************************************************************
00002 *  $Id: soap-nudp.c,v 1.9 2006/12/16 15:55:24 m0gg Exp $
00003 *
00004 * CSOAP Project:  A SOAP client/server library in C
00005 * Copyright (C) 2006 Heiko Ronsdorf
00006 *
00007 * This library is free software; you can redistribute it and/or
00008 * modify it under the terms of the GNU Library General Public
00009 * License as published by the Free Software Foundation; either
00010 * version 2 of the License, or (at your option) any later version.
00011 *
00012 * This library is distributed in the hope that it will be useful,
00013 * but WITHOUT ANY WARRANTY; without even the implied warranty of
00014 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00015 * Library General Public License for more details.
00016 *
00017 * You should have received a copy of the GNU Library General Public
00018 * License along with this library; if not, write to the
00019 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
00020 * Boston, MA  02111-1307, USA.
00021 * 
00022 * Email: hero@persua.de
00023 ******************************************************************/
00024 #ifdef HAVE_CONFIG_H
00025 #include <config.h>
00026 #endif
00027 
00028 #ifdef HAVE_SYS_TYPES_H
00029 #include <sys/types.h>
00030 #endif
00031 
00032 #ifdef HAVE_SYS_SOCKET_H
00033 #include <sys/socket.h>
00034 #endif
00035 
00036 #ifdef HAVE_STDLIB_H
00037 #include <stdlib.h>
00038 #endif
00039 
00040 #ifdef HAVE_STDIO_H
00041 #include <stdio.h>
00042 #endif
00043 
00044 #ifdef HAVE_STRING_H
00045 #include <string.h>
00046 #endif
00047 
00048 #ifdef HAVE_ERRNO_H
00049 #include <errno.h>
00050 #endif
00051 
00052 #ifdef HAVE_UNISTD_H
00053 #include <unistd.h>
00054 #endif
00055 
00056 #ifdef HAVE_PTHREAD_H
00057 #include <pthread.h>
00058 #endif
00059 
00060 #ifdef HAVE_NETDB_H
00061 #include <netdb.h>
00062 #endif
00063 
00064 #ifdef HAVE_NETINET_IN_H
00065 #include <netinet/in.h>
00066 #endif
00067 
00068 #ifdef HAVE_ARPA_INET_H
00069 #include <arpa/inet.h>
00070 #endif
00071 
00072 #include <libxml/tree.h>
00073 #include <libxml/uri.h>
00074 
00075 #include <nanohttp/nanohttp-error.h>
00076 #include <nanohttp/nanohttp-logging.h>
00077 
00078 #include "soap-fault.h"
00079 #include "soap-env.h"
00080 #include "soap-ctx.h"
00081 #include "soap-service.h"
00082 #include "soap-router.h"
00083 #include "soap-server.h"
00084 #include "soap-transport.h"
00085 #include "soap-addressing.h"
00086 #include "soap-nudp.h"
00087 
00088 static short _soap_nudp_port = NUDP_DEFAULT_PORT;
00089 static int _soap_nudp_socket;
00090 static pthread_t _soap_nudp_thread;
00091 static pthread_attr_t _soap_nudp_attr;
00092 static volatile int _soap_nudp_running = 0;
00093 
00094 static short
00095 _soap_nudp_server_set_port(void)
00096 {
00097   struct servent *entry;
00098 
00099   if (!(entry = getservbyname("soap", "udp")))
00100   {
00101     log_warn1("getservbyname(\"soap\", \"udp\") returned NULL, please edit services database");
00102     _soap_nudp_port = NUDP_DEFAULT_PORT;
00103   }
00104   else
00105   {
00106     _soap_nudp_port = ntohs(entry->s_port);
00107   }
00108   return _soap_nudp_port;
00109 }
00110 
00111 static void
00112 _soap_nudp_server_parse_arguments(int argc, char **argv)
00113 {
00114   int i;
00115 
00116   for (i=1; i<argc; i++)
00117   {
00118     if (!strcmp(argv[i - 1], NUDP_ARG_PORT))
00119     {
00120       _soap_nudp_port = atoi(argv[i]);
00121     }
00122   }
00123 
00124   log_verbose2("socket bind to port \"%d\"", _soap_nudp_port);
00125 
00126   return;
00127 }
00128 
00129 static herror_t
00130 _soap_nudp_send_document(int socket, xmlDocPtr doc, const struct sockaddr *addr, socklen_t addr_len)
00131 {
00132   xmlChar *buf;
00133   herror_t ret;
00134   int size;
00135   size_t sent;
00136 
00137   ret = H_OK;
00138 
00139   xmlDocDumpMemory(doc, &buf, &size);
00140   if ((sent = sendto(socket, buf, size, 0, addr, addr_len)) == -1)
00141   {
00142     log_error2("sendto failed (%s)", strerror(errno));
00143     ret = herror_new("soap_nudp_client_invoke", 0, "Cannot send message");
00144   }
00145 
00146   xmlFree(buf);
00147 
00148   return ret;
00149 }
00150 
00151 static herror_t
00152 _soap_nudp_receive_document(int socket, xmlDocPtr *doc, struct sockaddr *addr, socklen_t *addr_len)
00153 {
00154   int cnt;
00155   char buf[4096];
00156 
00158   if ((cnt = recvfrom(socket, buf, 4095, 0, addr, addr_len)) < 0)
00159   {
00160     log_error2("recvfrom failed (%s)", strerror(errno));
00161     return herror_new("_soap_nudp_receive_document", 0, "Receiving document failed");
00162   }
00163   buf[cnt] = '\0';
00164 
00165   if (!(*doc = xmlReadDoc(buf, NULL, NULL, XML_PARSE_NONET)))
00166   {
00167     log_error1("xmlReadDoc failed");
00168     return herror_new("_soap_nudp_receive_document", 0, "Cannot parse received data");
00169   }
00170 
00171   return H_OK;
00172 }
00173 
00174 static herror_t
00175 _soap_nudp_client_invoke(void *unused, struct SoapCtx *request, struct SoapCtx **response)
00176 {
00177   xmlURI *to;
00178   xmlDocPtr doc;
00179   int sd;
00180   herror_t status;
00181   struct sockaddr_in addr;
00182   struct sockaddr saddr;
00183   socklen_t saddr_len;
00184 
00185   if (!(to = soap_addressing_get_to_address(request->env)))
00186   {
00187     log_error1("soap_addressing_get_to_address returned NULL");
00188     return herror_new("soap_nudp_client_invoke", 0, "Destination address is missing");
00189   }
00190 
00191   bzero(&addr, sizeof(struct sockaddr_in));
00192   addr.sin_family = AF_INET;
00193   if (to->port == 0)
00194     addr.sin_port = htons(NUDP_DEFAULT_PORT);
00195   else
00196     addr.sin_port = htons(to->port);
00197 
00198   if (inet_pton(AF_INET, "127.0.0.1", &addr.sin_addr) != 1)
00199   {
00200     log_error2("inet_pton failed (%s)", strerror(errno));
00201     return herror_new("soap_nudp_client_invoke", 0, "Cannot resolve destination address");
00202   }
00203 
00204   if ((sd = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
00205   {
00206     log_error2("socket failed (%s)", strerror(errno));
00207     return herror_new("soap_nudp_client_invoke", 0, "Cannot create socket");
00208   }
00209 
00210   _soap_nudp_send_document(sd, request->env->root->doc, (struct sockaddr *)&addr, sizeof(struct sockaddr_in));
00211 
00212   saddr_len = sizeof(struct sockaddr);
00213   if ((status = _soap_nudp_receive_document(sd, &doc, &saddr, &saddr_len)) != H_OK)
00214   {
00215     log_error2("_soap_nudp_receive_document failed (%s)", herror_message(status));
00216     return status;
00217   }
00218 
00219   *response = soap_ctx_new(NULL);
00220   if ((status = soap_env_new_from_doc(doc, &(*response)->env)) != H_OK)
00221   {
00222     log_error2("soap_env_new_from_doc failed (%s)", herror_message(status));
00223     return status;
00224   }
00225 
00228   return H_OK;
00229 }
00230 
00231 herror_t
00232 soap_nudp_server_init_args(int argc, char **argv)
00233 {
00234   struct sockaddr_in addr;
00235 
00236   _soap_nudp_server_set_port();
00237 
00238   _soap_nudp_server_parse_arguments(argc, argv);
00239  
00240   if ((_soap_nudp_socket = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
00241   {
00242     log_error2("socket failed (%s)", strerror(errno));
00243     return herror_new("soap_nudp_server_init_args", 0, "Cannot create socket (%s)", strerror(errno));
00244   }
00245 
00246   memset(&addr, 0, sizeof(struct sockaddr_in));
00247   addr.sin_family = AF_INET;
00248   addr.sin_addr.s_addr = htonl(INADDR_ANY);
00249   addr.sin_port = htons(_soap_nudp_port);
00250 
00251   if (bind(_soap_nudp_socket, (struct sockaddr *)&addr, sizeof(struct sockaddr_in)) < 0)
00252   {
00253     log_error2("bind failed (%s)", strerror(errno));
00254     return herror_new("soap_nudp_server_init_args", 0, "Cannot bind socket (%s)", strerror(errno));
00255   }
00256 
00257   return H_OK;
00258 }
00259 
00260 herror_t
00261 soap_nudp_register(const void *data)
00262 {
00263   return H_OK;
00264 }
00265 
00266 void *
00267 soap_nudp_server_run(void *unused)
00268 {
00269   xmlDocPtr doc;
00270   struct sockaddr addr;
00271   socklen_t addr_len;
00272   struct SoapCtx *req;
00273   struct SoapCtx *res;
00274   xmlURI *to;
00275   herror_t status;
00276 
00277   while (_soap_nudp_running)
00278   {
00279     /* XXX: select with timeout */
00280 
00281     addr_len = sizeof(struct sockaddr);
00282     if (_soap_nudp_receive_document(_soap_nudp_socket, &doc, &addr, &addr_len) != H_OK)
00283     {
00284       log_error2("_soap_nudp_receive_document failed (%s)", herror_message(status));
00285       herror_release(status);
00286       continue;
00287     }
00288 
00289     /* log_error1(__FUNCTION__);
00290      xmlDocFormatDump(stdout, doc, 1); */
00291 
00292     req = soap_ctx_new(NULL);
00293 
00294     soap_env_new_from_doc(doc, &(req->env));
00295 
00296     /* only local part is interesting */
00297     to = soap_addressing_get_to_address(req->env);
00298     soap_addressing_set_to_address_string(req->env, to->path);
00299 
00300     // xmlFreeDoc(doc);
00301 
00302     soap_transport_process(req, &res);
00303 
00304     xmlDocFormatDump(stderr, res->env->root->doc, 1);
00305 
00306     _soap_nudp_send_document(_soap_nudp_socket, res->env->root->doc, &addr, addr_len);
00307 
00308     soap_ctx_free(res);
00309 
00310     soap_ctx_free(req);
00311   }
00312  
00313   close(_soap_nudp_socket);
00314 
00315   return NULL;
00316 }
00317 
00318 herror_t
00319 soap_nudp_server_run_threaded(void)
00320 {
00321   int err;
00322   
00323   _soap_nudp_running = 1;
00324 
00325   if ((err = pthread_create(&_soap_nudp_thread, &_soap_nudp_attr, soap_nudp_server_run, NULL)) < 0)
00326   {
00327     log_error2("pthread_create failed (%s)", strerror(err));
00328     return herror_new("soap_nudp_server_run_threaded", 0, "pthread_create failed (%s)", strerror(err));
00329   }
00330 
00331   return H_OK;
00332 }
00333 
00334 void
00335 soap_nudp_server_destroy(void)
00336 {
00337   _soap_nudp_running = 0;
00338 
00339   /* XXX: sleep for timeout, wait for select */
00340 
00341   return;
00342 }
00343 
00344 herror_t
00345 soap_nudp_client_init_args(int argc, char **argv)
00346 {
00347   soap_transport_add("soap.udp", NULL, _soap_nudp_client_invoke);
00348 
00349   return H_OK;
00350 }
00351 
00352 void
00353 soap_nudp_client_destroy(void)
00354 {
00355   return;
00356 }

Generated on Thu Jan 25 23:36:03 2007 for csoap by  doxygen 1.4.6