--- /dev/null
+all:
+ @source install.conf && make -s -C src all
+
+jserver:
+ @source install.conf && make -s -C src jserver
+
+install:
+ @source install.conf && make -s -C src install
+
+jserver-install:
+ @source install.conf && make -s -C src jserver-install
+
+clean:
+ @make -s -C src clean
--- /dev/null
+<?xml version="1.0" encoding="UTF-8" ?>
+
+<!--
+
+Copyright (C) 2007 Laurentian University
+Dan Scott <dscott@laurentian.ca>
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+
+-->
+
+<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
+
+<!-- define types -->
+<xs:simpleType name="loglevelType">
+ <xs:restriction base="xs:positiveInteger">
+ <xs:maxInclusive value="4"/>
+ </xs:restriction>
+</xs:simpleType>
+
+<xs:simpleType name="portType">
+ <xs:restriction base="xs:positiveInteger">
+ <xs:maxInclusive value="65535"/>
+ </xs:restriction>
+</xs:simpleType>
+
+
+<!-- define simple elements -->
+<xs:element name="router_name" type="xs:string"/>
+<xs:element name="domain" type="xs:string"/>
+<xs:element name="username" type="xs:string"/>
+<xs:element name="passwd" type="xs:string"/>
+<xs:element name="port" type="portType"/>
+<xs:element name="logfile" type="xs:string"/>
+<xs:element name="loglevel" type="loglevelType"/>
+
+<!-- group type -->
+<xs:group name="srfshElements">
+ <xs:all>
+ <xs:element ref="router_name"/>
+ <xs:element ref="domains"/>
+ <xs:element ref="username"/>
+ <xs:element ref="passwd"/>
+ <xs:element ref="port"/>
+ <xs:element ref="logfile"/>
+ <xs:element ref="loglevel"/>
+ </xs:all>
+</xs:group>
+
+<!-- complex elements -->
+<xs:element name="domains">
+ <xs:complexType>
+ <xs:sequence>
+ <xs:element ref="domain" minOccurs="1" maxOccurs="unbounded"/>
+ </xs:sequence>
+ </xs:complexType>
+</xs:element>
+
+<xs:element name="srfsh">
+ <xs:complexType>
+ <xs:group ref="srfshElements"/>
+ </xs:complexType>
+</xs:element>
+
+</xs:schema>
--- /dev/null
+export PREFIX=/openils/
+export BINDIR=/openils//bin/
+export LIBDIR=/openils//lib/
+export PERLDIR=/openils//lib//perl5/
+export INCLUDEDIR=/openils//include/
+export ETCDIR=/openils//conf
+export SOCK=/openils//var/sock
+export PID=/openils//var/pid
+export LOG=/openils//var/log
+export TMP=/tmp/ilstemp
+export APXS2=/usr/bin/apxs2
+export APACHE2_HEADERS=/usr/include/apache2
+export APR_HEADERS=/usr/include/apr-1.0/
+export LIBXML2_HEADERS=/usr/include/libxml2/
export INCLUDEDIR = $(PREFIX)/include
export LDLIBS +=
-export LDFLAGS += -L $(TMPDIR) -L . -L /opt/lib
+export LDFLAGS += -Wl,-rpath=$(LIBDIR) -L $(TMPDIR) -L . -L /opt/lib
export CFLAGS += -pipe -g -Wall -O2 -fPIC -I$(LIBXML2_HEADERS) -I$(APACHE2_HEADERS) \
-I$(LIBXML2_HEADERS)/libxml -I$(TMP) \
-I$(APR_HEADERS) -I$(TMPDIR)
mkdir -p $(INCLUDEDIR)
mkdir -p $(INCLUDEDIR)/$(OPENSRF)
mkdir -p $(ETCDIR)
- mkdir -p $(TEMPLATEDIR)
libopensrf-install: install-prep
@echo $@
JAVA_LIBDIR = .lib
JAVAC=javac -J-Xmx256m
JAVA=java -Xmx256m
-JAVA_LIBS = .:$(JAVA_LIBDIR):ext/json-jdk1.5-2007-05-01.jar:ext/wstx-asl-3.2.1.jar:ext/stax-api-1.0.1.jar
+JAVA_LIBS = .:$(JAVA_LIBDIR):ext/json-jdk1.5-2007-05-01.jar:ext/wstx-lgpl-3.2.1.jar:ext/stax-api-1.0.1.jar:ext/java_memcached-release_1.5.1.jar
JAVA_SRC = \
org/opensrf/net/xmpp/*.java \
org/opensrf/util/*.java \
@echo -e "\nTruncating at 30 lines"
run:
- $(JAVA) -cp $(JAVA_LIBS) $(JAVA_EXE) $(JAVA_ARGS)
+ @$(JAVA) -cp $(JAVA_LIBS) $(JAVA_EXE) $(JAVA_ARGS)
+
+deps:
+ mkdir -p ext
+ wget 'http://woodstox.codehaus.org/stax-api-1.0.1.jar' -O ext/stax-api-1.0.1.jar
+ wget 'http://woodstox.codehaus.org/3.2.1/wstx-lgpl-3.2.1.jar' -O ext/wstx-lgpl-3.2.1.jar
+ wget 'http://img.whalin.com/memcached/jdk5/standard/java_memcached-release_1.5.1.jar' -O ext/java_memcached-release_1.5.1.jar
+ mkdir -p .tmp && cd .tmp && wget 'http://www.json.org/java/json.zip' && unzip json.zip
+ $(JAVAC) -d $(JAVA_LIBDIR) .tmp/org/json/*.java
docs:
find . -name *.java > files;
import java.util.Arrays;
import org.opensrf.util.*;
+import org.opensrf.net.xmpp.*;
/**
this.service = service;
/** generate the remote node string */
- domain = (String) Config.getFirst("/domains/domain");
- router = Config.getString("/router_name");
+ domain = (String) Config.global().getFirst("/domains/domain");
+ router = Config.global().getString("/router_name");
setRemoteNode(router + "@" + domain + "/" + service);
origRemoteNode = getRemoteNode();
*/
public void pushResponse(Message msg) {
- Request req = requests.get(new Integer(msg.getId()));
+ Request req = findRequest(msg.getId());
if(req == null) {
/** LOG that we've received a result to a non-existant request */
return;
);
}
+ public Request findRequest(int reqId) {
+ return requests.get(new Integer(reqId));
+ }
+
/**
* Removes a request for this session's request set
*/
public void cleanupRequest(int reqId) {
requests.remove(new Integer(reqId));
}
+
+ public void setRequestComplete(int reqId) {
+ Request req = findRequest(reqId);
+ if(req == null) return;
+ req.setComplete();
+ }
}
* negative, this method will wait indefinitely.
* @return The result or null if none arrives in time
*/
- public Result recv(long millis) throws SessionException {
+ public Result recv(long millis) throws SessionException, MethodException {
Result result = null;
- if(millis < 0) {
+ if(millis < 0 && !complete) {
/** wait potentially forever for a result to arrive */
session.waitForMessage(millis);
if((result = resultQueue.poll()) != null)
} else {
- while(millis >= 0) {
+ while(millis >= 0 && !complete) {
/** wait up to millis milliseconds for a result. waitForMessage()
* will return if a response to any request arrives, so we keep track
public void cleanup() {
session.cleanupRequest(id);
}
+
+ /** Sets this request as complete */
+ public void setComplete() {
+ complete = true;
+ }
}
* all received messages to the stack for processing
* @param millis The number of milliseconds to wait for a message to arrive
*/
- public static void waitForMessage(long millis) throws SessionException {
+ public static void waitForMessage(long millis) throws SessionException, MethodException {
try {
Stack.processXMPPMessage(
XMPPSession.getGlobalSession().recv(millis));
--- /dev/null
+package org.opensrf;
+/**
+ * Used by sessions to indicate communication errors
+ */
+public class SessionException extends Exception {
+ public SessionException(String info) {
+ super(info);
+ }
+ public SessionException(String info, Throwable cause) {
+ super(info, cause);
+ }
+}
+
public class Stack {
- public static void processXMPPMessage(XMPPMessage msg) {
+ public static void processXMPPMessage(XMPPMessage msg) throws MethodException {
if(msg == null) return;
+ //System.out.println(msg.getBody());
+
/** fetch this session from the cache */
Session ses = Session.findCachedSession(msg.getThread());
/** LOG the duration */
}
- private static void processOSRFMessage(Session ses, Message msg) {
+ private static void processOSRFMessage(Session ses, Message msg) throws MethodException {
if( ses instanceof ClientSession )
processResponse((ClientSession) ses, msg);
else
/**
* Process a server response
*/
- private static void processResponse(ClientSession session, Message msg) {
- if(msg.RESULT.equals(msg.getType())) {
+ private static void processResponse(ClientSession session, Message msg) throws MethodException {
+ String type = msg.getType();
+
+ if(msg.RESULT.equals(type)) {
session.pushResponse(msg);
return;
}
+
+ if(msg.STATUS.equals(type)) {
+
+ OSRFObject obj = (OSRFObject) msg.getPayload();
+ Status stat = new Status(obj.getString("status"), obj.getInt("statusCode"));
+ int statusCode = stat.getStatusCode();
+ String status = stat.getStatus();
+
+ switch(statusCode) {
+ case Status.COMPLETE:
+ session.setRequestComplete(msg.getId());
+ break;
+ case Status.NOTFOUND:
+ session.setRequestComplete(msg.getId());
+ throw new MethodException(status);
+ }
+ }
}
/**
--- /dev/null
+package org.opensrf;
+import org.opensrf.util.*;
+
+public class Status {
+
+ public static final int CONTINUE = 100;
+ public static final int OK = 200;
+ public static final int ACCEPTED = 202;
+ public static final int COMPLETE = 205;
+ public static final int REDIRECTED = 307;
+ public static final int EST = 400;
+ public static final int STATUS_UNAUTHORIZED = 401;
+ public static final int FORBIDDEN = 403;
+ public static final int NOTFOUND = 404;
+ public static final int NOTALLOWED = 405;
+ public static final int TIMEOUT = 408;
+ public static final int EXPFAILED = 417;
+ public static final int INTERNALSERVERERROR = 500;
+ public static final int NOTIMPLEMENTED = 501;
+ public static final int VERSIONNOTSUPPORTED = 505;
+
+ private OSRFRegistry registry = OSRFRegistry.registerObject(
+ "osrfConnectStatus",
+ OSRFRegistry.WireProtocol.HASH,
+ new String[] {"status", "statusCode"});
+
+ /** The name of the status */
+ String status;
+ /** The status code */
+ int statusCode;
+
+ public Status(String status, int statusCode) {
+ this.status = status;
+ this.statusCode = statusCode;
+ }
+
+ public int getStatusCode() {
+ return statusCode;
+ }
+ public String getStatus() {
+ return status;
+ }
+
+ /**
+ * Implements the generic get() API required by OSRFSerializable
+ */
+ public Object get(String field) {
+ if("status".equals(field))
+ return getStatus();
+ if("statusCode".equals(field))
+ return new Integer(getStatusCode());
+ return null;
+ }
+
+ /**
+ * @return The osrfMessage registry.
+ */
+ public OSRFRegistry getRegistry() {
+ return registry;
+ }
+}
+
+
--- /dev/null
+package org.opensrf;
+
+import org.opensrf.util.*;
+import org.opensrf.net.xmpp.*;
+
+
+public class Sys {
+
+ /**
+ * Connects to the OpenSRF network so that client sessions may communicate.
+ * @param configFile The OpenSRF config file
+ * @param configContext Where in the XML document the config chunk lives. This
+ * allows an OpenSRF client config chunk to live in XML files where other config
+ * information lives.
+ */
+ public static void bootstrapClient(String configFile, String configContext)
+ throws ConfigException, SessionException {
+
+ /** create the config parser */
+ Config config = new Config(configContext);
+ config.parse(configFile);
+ Config.setConfig(config); /* set this as the global config */
+
+ /** Collect the network connection info from the config */
+ String username = config.getString("/username");
+ String passwd = config.getString("/passwd");
+ String host = (String) config.getFirst("/domains/domain");
+ int port = config.getInt("/port");
+
+ try {
+ /** Connect to the Jabber network */
+ XMPPSession xses = new XMPPSession(host, port);
+ xses.connect(username, passwd, "test-java"); /* XXX */
+ XMPPSession.setGlobalSession(xses);
+ } catch(XMPPException e) {
+ throw new SessionException("Unable to bootstrap client", e);
+ }
+ }
+
+ /**
+ * Shuts down the connection to the opensrf network
+ */
+ public static void shutdown() {
+ XMPPSession.getGlobalSession().disconnect();
+ }
+}
+
"<iq id='123' type='set'><query xmlns='jabber:iq:auth'>" +
"<username>%s</username><password>%s</password><resource>%s</resource></query></iq>";
+ public static final String JABBER_DISCONNECT = "</stream:stream>";
+
/** jabber domain */
private String host;
/** jabber port */
PrintWriter writer;
/** Raw socket output stream */
OutputStream outStream;
+ /** The raw socket */
+ Socket socket;
/** The process-wide session. All communication occurs
* accross this single connection */
this.password = password;
this.resource = resource;
- Socket socket;
-
try {
/* open the socket and associated streams */
socket = new Socket(host, port);
return null;
}
+
+
+ /**
+ * Disconnects from the jabber server and closes the socket
+ */
+ public void disconnect() {
+ try {
+ outStream.write(JABBER_DISCONNECT.getBytes());
+ socket.close();
+ } catch(Exception e) {}
+ }
}
--- /dev/null
+package org.opensrf.test;
+import org.opensrf.*;
+import org.opensrf.util.*;
+import java.util.Date;
+import java.util.List;
+import java.util.ArrayList;
+import java.io.PrintStream;
+
+
+public class MathBench {
+
+ public static void main(String args[]) throws Exception {
+
+ PrintStream out = System.out;
+
+ if(args.length < 2) {
+ out.println("usage: java org.opensrf.test.MathBench <osrfConfig> <numIterations>");
+ return;
+ }
+
+ /** connect to the opensrf network */
+ Sys.bootstrapClient(args[0], "/config/opensrf");
+
+ /** how many iterations */
+ int count = Integer.parseInt(args[1]);
+
+ /** create the client session */
+ ClientSession session = new ClientSession("opensrf.math");
+
+ /** params are 1,2 */
+ List<Object> params = new ArrayList<Object>();
+ params.add(new Integer(1));
+ params.add(new Integer(2));
+
+ Request request;
+ Result result;
+ long start;
+ double total = 0;
+
+ for(int i = 0; i < count; i++) {
+
+ start = new Date().getTime();
+
+ /** create (and send) the request */
+ request = session.request("add", params);
+
+ /** wait up to 3 seconds for a response */
+ result = request.recv(3000);
+
+ /** collect the round-trip time */
+ total += new Date().getTime() - start;
+
+ if(result.getStatusCode() == Status.OK) {
+ out.print("+");
+ } else {
+ out.println("\nrequest failed");
+ out.println("status = " + result.getStatus());
+ out.println("status code = " + result.getStatusCode());
+ }
+
+ /** remove this request from the session's request set */
+ request.cleanup();
+
+ if((i+1) % 100 == 0) /** print 100 responses per line */
+ out.println(" [" + (i+1) + "]");
+ }
+
+ out.println("\nAverage request time is " + (total/count) + " ms");
+
+ /** remove this session from the global session cache */
+ session.cleanup();
+
+ /** disconnect from the opensrf network */
+ Sys.shutdown();
+ }
+}
+
+
+
--- /dev/null
+package org.opensrf.test;
+import org.opensrf.*;
+import org.opensrf.util.*;
+import java.util.List;
+import java.util.ArrayList;
+
+public class TestCache {
+ public static void main(String args[]) throws Exception {
+
+ /**
+ * args is a list of string like so: server:port server2:port server3:port ...
+ */
+
+ Cache.initCache(args);
+ Cache cache = new Cache();
+
+ cache.set("key1", "HI, MA!");
+ cache.set("key2", "HI, MA! 2");
+ cache.set("key3", "HI, MA! 3");
+
+ System.out.println("got key1 = " + (String) cache.get("key1"));
+ System.out.println("got key2 = " + (String) cache.get("key2"));
+ System.out.println("got key3 = " + (String) cache.get("key3"));
+ }
+}
+
+
package org.opensrf.test;
import org.opensrf.*;
import org.opensrf.util.*;
-import org.opensrf.net.xmpp.*;
-import java.io.PrintStream;
import java.util.Map;
import java.util.Date;
+import java.util.List;
+import java.util.ArrayList;
+import java.io.PrintStream;
public class TestClient {
+
public static void main(String args[]) throws Exception {
-
+
PrintStream out = System.out;
+ if(args.length < 3) {
+ out.println( "usage: org.opensrf.test.TestClient "+
+ "<osrfConfigFile> <service> <method> [<JSONparam1>, <JSONparam2>]");
+ return;
+ }
- try {
-
- /** setup the config parser */
- String configFile = args[0];
- Config config = new Config("/config/opensrf");
- config.parse(configFile);
- Config.setConfig(config);
-
- /** Connect to jabber */
- String username = Config.getString("/username");
- String passwd = Config.getString("/passwd");
- String host = (String) Config.getFirst("/domains/domain");
- int port = Config.getInt("/port");
- XMPPSession xses = new XMPPSession(host, port);
- xses.connect(username, passwd, "test-java-client");
- XMPPSession.setGlobalSession(xses);
-
- /** build the client session and send the request */
- ClientSession session = new ClientSession("opensrf.settings");
- Request request = session.request(
- "opensrf.settings.host_config.get",
- new String[] {args[1]}
- );
-
- Result result = request.recv(10000);
- if(result == null) {
- out.println("no result");
- return;
- }
+ Sys.bootstrapClient(args[0], "/config/opensrf");
+ String service = args[1];
+ String method = args[2];
- out.println("status = " + result.getStatus());
- out.println("status code = " + result.getStatusCode());
+ /** build the client session and send the request */
+ ClientSession session = new ClientSession(service);
+ List<Object> params = new ArrayList<Object>();
+ JSONReader reader;
- out.println("setting config memcache server(s) = " +
- new JSONWriter(
- Utils.findPath( (Map) result.getContent(),
- "/cache/global/servers/server")
- ).write());
+ for(int i = 3; i < args.length; i++) /* add the params */
+ params.add(new JSONReader(args[i]).read());
- } catch(ArrayIndexOutOfBoundsException e) {
- out.println("usage: org.opensrf.test.TestClient <osrfConfigFile> <domain>");
- return;
+ Result result;
+
+ long start = new Date().getTime();
+ Request request = session.request(method, params);
+
+ while( (result = request.recv(60000)) != null ) {
+ /** loop over the results and print the JSON version of the content */
+
+ if(result.getStatusCode() != 200) { /* make sure the request succeeded */
+ out.println("status = " + result.getStatus());
+ out.println("status code = " + result.getStatusCode());
+ continue;
+ }
+
+ out.println("result JSON: " + new JSONWriter(result.getContent()).write());
}
+ out.println("Request round trip took: " + (new Date().getTime() - start) + " ms.");
}
}
System.out.println("");
for(int i = 1; i < args.length; i++)
- System.out.println("Found config value: " + args[i] + ": " + Config.get(args[i]));
+ System.out.println("Found config value: " + args[i] + ": " + Config.global().get(args[i]));
}
}
--- /dev/null
+package org.opensrf.test;
+import org.opensrf.*;
+import org.opensrf.util.*;
+
+public class TestSettings {
+ public static void main(String args[]) throws Exception {
+ Sys.bootstrapClient(args[0], "/config/opensrf");
+ SettingsClient client = SettingsClient.instance();
+ String lang = client.getString("/apps/opensrf.settings/language");
+ String impl = client.getString("/apps/opensrf.settings/implementation");
+ System.out.println("opensrf.settings language = " + lang);
+ System.out.println("opensrf.settings implementation = " + impl);
+ }
+}
--- /dev/null
+package org.opensrf.util;
+import com.danga.MemCached.*;
+import java.util.List;
+
+/**
+ * Memcache client
+ */
+public class Cache extends MemCachedClient {
+
+ public Cache() {
+ super();
+ setCompressThreshold(4096); /* ?? */
+ }
+
+ /**
+ * Initializes the cache client
+ * @param serverList Array of server:port strings specifying the
+ * set of memcache servers this client will talk to
+ */
+ public static void initCache(String[] serverList) {
+ SockIOPool pool = SockIOPool.getInstance();
+ pool.setServers(serverList);
+ pool.initialize();
+ com.danga.MemCached.Logger logger =
+ com.danga.MemCached.Logger.getLogger(MemCachedClient.class.getName());
+ logger.setLevel(logger.LEVEL_ERROR);
+ }
+
+ /**
+ * Initializes the cache client
+ * @param serverList List of server:port strings specifying the
+ * set of memcache servers this client will talk to
+ */
+ public static void initCache(List<String> serverList) {
+ initCache(serverList.toArray(new String[]{}));
+ }
+}
+
*/
private String context;
+ public static Config global() {
+ return config;
+ }
+
+
/**
* @param context The config context
*/
* Sets the global config object.
* @param c The config object to use.
*/
- public static void setConfig(Config c) {
+ public static void setGlobalConfig(Config c) {
config = c;
}
* Parses an XML config file.
* @param filename The path to the file to parse.
*/
- public void parse(String filename) throws Exception {
- String xml = Utils.fileToString(filename);
- JSONObject jobj = XML.toJSONObject(xml);
- configObject = (Map) new JSONReader(jobj.toString()).readObject();
+ public void parse(String filename) throws ConfigException {
+ try {
+ String xml = Utils.fileToString(filename);
+ JSONObject jobj = XML.toJSONObject(xml);
+ configObject = (Map) new JSONReader(jobj.toString()).readObject();
+ } catch(Exception e) {
+ throw new ConfigException("Error parsing config", e);
+ }
}
+ public static void setConfig(Config conf) {
+ config = conf;
+ }
+
+ public void setConfigObject(Map config) {
+ this.configObject = config;
+ }
+
+ protected Map getConfigObject() {
+ return this.configObject;
+ }
+
+
/**
* Returns the configuration value found at the requested path.
* @param path The search path
* @return The config value, or null if no value exists at the given path.
* @throws ConfigException thrown if nothing is found at the path
*/
- public static String getString(String path) throws ConfigException {
+ public String getString(String path) throws ConfigException {
try {
return (String) get(path);
} catch(Exception e) {
* Gets the int value at the given path
* @param path The search path
*/
- public static int getInt(String path) throws ConfigException {
+ public int getInt(String path) throws ConfigException {
try {
return Integer.parseInt(getString(path));
} catch(Exception e) {
* @return The config value
* @throws ConfigException thrown if nothing is found at the path
*/
- public static Object get(String path) throws ConfigException {
+ public Object get(String path) throws ConfigException {
try {
- Object obj = Utils.findPath(config.configObject, config.context + path);
+ Object obj = Utils.findPath(configObject, context + path);
if(obj == null)
throw new ConfigException("");
return obj;
* no list is found, ConfigException is thrown.
* @param path The search path
*/
- public static Object getFirst(String path) throws ConfigException {
+ public Object getFirst(String path) throws ConfigException {
Object obj = get(path);
if(obj instanceof List)
return ((List) obj).get(0);
public ConfigException(String info) {
super(info);
}
+ public ConfigException(String info, Throwable t) {
+ super(info, t);
+ }
}
--- /dev/null
+package org.opensrf.util;
+import org.opensrf.*;
+import java.util.Map;
+
+/**
+ * Connects to the OpenSRF Settings server to fetch the settings config.
+ * Provides a Config interface for fetching settings via path
+ */
+public class SettingsClient extends Config {
+
+ /** Singleton SettingsClient instance */
+ private static SettingsClient client = new SettingsClient();
+
+ public SettingsClient() {
+ super("");
+ }
+
+ /**
+ * @return The global settings client instance
+ */
+ public static SettingsClient instance() throws ConfigException {
+ if(client.getConfigObject() == null)
+ client.fetchConfig();
+ return client;
+ }
+
+ /**
+ * Fetches the settings object from the settings server
+ */
+ private void fetchConfig() throws ConfigException {
+
+ ClientSession ses = new ClientSession("opensrf.settings");
+ try {
+
+ Request req = ses.request(
+ "opensrf.settings.host_config.get",
+ new String[]{(String)Config.global().getFirst("/domains/domain")});
+
+ Result res = req.recv(12000);
+ if(res == null) {
+ /** throw exception */
+ }
+ setConfigObject((Map) res.getContent());
+
+ } catch(Exception e) {
+ throw new ConfigException("Error fetching settings config", e);
+
+ } finally {
+ ses.cleanup();
+ }
+ }
+}
+
#include <stdio.h>
#include <time.h>
-int __osrfChatXMLErrorOcurred = 0;
-int __osrfChatClientSentDisconnect = 0;
+static int osrfChatXMLErrorOcurred = 0;
+static int osrfChatClientSentDisconnect = 0;
/* shorter version of strcmp */
static int eq(const char* a, const char* b) { return (a && b && !strcmp(a,b)); }
server->deadNodes = osrfNewList();
server->nodeList->freeItem = &osrfChatNodeFree;
server->domain = strdup(domain);
+ server->secret = strdup(secret);
server->s2sport = s2sport;
+ server->port = 0;
+ // Build socket manager
server->mgr = safe_malloc(sizeof(socket_manager));
server->mgr->data_received = &osrfChatHandleData;
server->mgr->blob = server;
server->mgr->on_socket_closed = &osrfChatSocketClosed;
- if(secret) server->secret = strdup(secret);
return server;
}
if(!server) return;
osrfHashFree(server->nodeHash);
osrfListFree(server->nodeList);
+ osrfListFree(server->deadNodes);
free(server->mgr);
+ free(server->domain);
free(server->secret);
+
+ free(server);
}
xmlParseChunk(node->parserCtx, data, strlen(data), 0);
node->inparse = 0;
- if(__osrfChatXMLErrorOcurred) {
- __osrfChatXMLErrorOcurred = 0;
+ if(osrfChatXMLErrorOcurred) {
+ osrfChatXMLErrorOcurred = 0;
return -1;
}
/* we can't do cleanup of the XML handlers while in the middle of a
data push, so set flags in the data push and doe the cleanup here */
/*
- if(__osrfChatClientSentDisconnect) {
- __osrfChatClientSentDisconnect = 0;
+ if(osrfChatClientSentDisconnect) {
+ osrfChatClientSentDisconnect = 0;
osrfChatNodeFinish( server, node );
}
*/
char* osrfChatMkAuthKey() {
char keybuf[112];
bzero(keybuf, 112);
- snprintf(keybuf, 111, "%d%d%s", (int) time(NULL), getpid(), getenv("HOSTNAME"));
+ snprintf(keybuf, 111, "%d%ld%s", (int) time(NULL), (long) getpid(), getenv("HOSTNAME"));
return strdup(shahash(keybuf));
}
void osrfChatParseError( void* blob, const char* msg, ... ) {
- __osrfChatXMLErrorOcurred = 1;
+ osrfChatXMLErrorOcurred = 1;
}
}
osrfConfig* cfg = osrfConfigInit( argv[1], argv[2] );
+ if( !cfg ) {
+ fprintf( stderr, "Unable to load configuration file %s\n", argv[1] );
+ return -1;
+ }
init_proc_title( argc, argv );
set_proc_title( "ChopChop" );
char* lfile = osrfConfigGetValue(cfg, "/logfile");
char* facility = osrfConfigGetValue(cfg, "/syslog");
+ if(!domain)
+ fputs( "No domain specified in configuration file\n", stderr );
+
+ if(!secret)
+ fputs( "No secret specified in configuration file\n", stderr );
+
+ if(!sport)
+ fputs( "No port specified in configuration file\n", stderr );
+
+ if(!listenaddr)
+ fputs( "No listen_address specified in configuration file\n", stderr );
+
+ if(!llevel)
+ fputs( "No loglevel specified in configuration file\n", stderr );
+
+ if(!lfile)
+ fputs( "No logfile specified in configuration file\n", stderr );
+
+ if(!s2sport)
+ fputs( "No s2sport specified in configuration file\n", stderr );
+
if(!(domain && secret && sport && listenaddr && llevel && lfile && s2sport)) {
fprintf(stderr, "Configuration error for ChopChop - missing key ingredient\n");
return -1;
int s2port = atoi(s2sport);
int level = atoi(llevel);
- if(!lfile) { fprintf(stderr, "Log file needed\n"); return -1; }
-
if(!strcmp(lfile, "syslog")) {
- osrfLogInit( OSRF_LOG_TYPE_SYSLOG, "chochop", level );
+ osrfLogInit( OSRF_LOG_TYPE_SYSLOG, "chopchop", level );
osrfLogSetSyslogFacility(osrfLogFacilityToInt(facility));
} else {
init_proc_title( argc, argv );
set_proc_title( "OpenSRF System-C" );
- osrfSystemBootstrap( host, config, context );
+ int ret = osrfSystemBootstrap( host, config, context );
+
+ if (ret != 0) {
+ osrfLogError(
+ OSRF_LOG_MARK,
+ "Server Loop returned an error condition, exiting with %d",
+ ret
+ );
+ }
+
free(host);
free(config);
free(context);
- return 0;
+ return ret;
}
/* defines the currently used bootstrap config file */
#include "osrfConfig.h"
-osrfConfig* __osrfConfigDefault = NULL;
+static osrfConfig* osrfConfigDefault = NULL;
void osrfConfigSetDefaultConfig(osrfConfig* cfg) {
- if(cfg) __osrfConfigDefault = cfg;
+ if(cfg) {
+ if( osrfConfigDefault )
+ osrfConfigFree( osrfConfigDefault );
+ osrfConfigDefault = cfg;
+ }
}
void osrfConfigFree(osrfConfig* cfg) {
int osrfConfigHasDefaultConfig() {
- return ( __osrfConfigDefault != NULL );
+ return ( osrfConfigDefault != NULL );
}
void osrfConfigCleanup() {
- osrfConfigFree(__osrfConfigDefault);
- __osrfConfigDefault = NULL;
+ osrfConfigFree(osrfConfigDefault);
+ osrfConfigDefault = NULL;
}
osrfConfig* osrfConfigInit(char* configFile, char* configContext) {
if(!configFile) return NULL;
- osrfConfigFree(__osrfConfigDefault);
-
- osrfConfig* cfg = safe_malloc(sizeof(osrfConfig));
- if(configContext) cfg->configContext = strdup(configContext);
- else cfg->configContext = NULL;
-
+ // Load XML from the configuration file
+
xmlDocPtr doc = xmlParseFile(configFile);
if(!doc) {
osrfLogWarning( OSRF_LOG_MARK, "Unable to parse XML config file %s", configFile);
return NULL;
}
- cfg->config = xmlDocToJSON(doc);
+ // Translate it into a jsonObject
+
+ jsonObject* json_config = xmlDocToJSON(doc);
/*
char* j = jsonObjectToJSON(cfg->config);
xmlFreeDoc(doc);
- if(!cfg->config) {
+ if(!json_config ) {
osrfLogWarning( OSRF_LOG_MARK, "xmlDocToJSON failed for config %s", configFile);
return NULL;
}
+ // Build an osrfConfig and return it by pointer
+
+ osrfConfig* cfg = safe_malloc(sizeof(osrfConfig));
+
+ if(configContext) cfg->configContext = strdup(configContext);
+ else cfg->configContext = NULL;
+
+ cfg->config = json_config;
+
return cfg;
}
char* osrfConfigGetValue(osrfConfig* cfg, char* path, ...) {
if(!path) return NULL;
- if(!cfg) cfg = __osrfConfigDefault;
- if(!cfg) { osrfLogWarning( OSRF_LOG_MARK, "No Confif object!"); return NULL; }
+ if(!cfg) cfg = osrfConfigDefault;
+ if(!cfg) { osrfLogWarning( OSRF_LOG_MARK, "No Config object in osrfConfigGetValue()"); return NULL; }
VA_LIST_TO_STRING(path);
int osrfConfigGetValueList(osrfConfig* cfg, osrfStringArray* arr, char* path, ...) {
if(!arr || !path) return 0;
- if(!cfg) cfg = __osrfConfigDefault;
+ if(!cfg) cfg = osrfConfigDefault;
if(!cfg) { osrfLogWarning( OSRF_LOG_MARK, "No Config object!"); return -1;}
VA_LIST_TO_STRING(path);
char id[256];
memset(id,0,256);
- sprintf(id, "%f.%d%d", get_timestamp_millis(), (int)time(NULL), getpid());
+ sprintf(id, "%f.%d%ld", get_timestamp_millis(), (int)time(NULL), (long) getpid());
session->session_id = strdup(id);
osrfLogDebug( OSRF_LOG_MARK, "Building a new client session with id [%s] [%s]",
session->remote_service, session->session_id );
if(!ses || ! data ) return -1;
osrf_message* msg = osrf_message_init( RESULT, requestId, 1 );
+ osrf_message_set_status_info( msg, NULL, "OK", OSRF_STATUS_OK );
char* json = jsonObjectToJSON( data );
osrf_message_set_result_content( msg, json );
if( errno == EAGAIN ) n = 0;
if( errno == EPIPE ) {
- osrfLogWarning(OSRF_LOG_MARK, "C child attempted read on broken pipe, exiting...");
+ osrfLogDebug(OSRF_LOG_MARK, "C child attempted read on broken pipe, exiting...");
break;
}
buffer_free(gbuf);
- osrfLogDebug( OSRF_LOG_MARK, "Child with max-requests=%d, num-served=%d exiting...[%d]",
- child->max_requests, i, getpid() );
+ osrfLogDebug( OSRF_LOG_MARK, "Child with max-requests=%d, num-served=%d exiting...[%ld]",
+ child->max_requests, i, (long) getpid() );
osrf_prefork_child_exit(child); /* just to be sure */
}
char* osrf_settings_host_value(char* format, ...) {
VA_LIST_TO_STRING(format);
+
+ if( ! config ) {
+ const char * msg = "NULL config pointer";
+ fprintf( stderr, "osrf_settings_host_value: %s\n", msg );
+ osrfLogError( OSRF_LOG_MARK, msg );
+ exit( 99 );
+ }
+
jsonObject* o = jsonObjectFindPath(config->config, VA_BUF);
char* val = jsonObjectToSimpleString(o);
jsonObjectFree(o);
osrf_message* omsg = osrf_app_session_request_recv( session, req_id, 60 );
jsonObjectFree(params);
- if(omsg && omsg->_result_content) {
+ if(!omsg) {
+ osrfLogError( OSRF_LOG_MARK, "No osrf_message received from host %s (timeout?)", hostname);
+ } else if(!omsg->_result_content) {
+ osrf_message_free(omsg);
+ osrfLogError(
+ OSRF_LOG_MARK,
+ "NULL or non-existant osrf_message result content received from host %s, "
+ "broken message or no settings for host",
+ hostname
+ );
+ } else {
config = osrf_settings_new_host_config(hostname);
config->config = jsonObjectClone(omsg->_result_content);
osrf_message_free(omsg);
#include "osrf_application.h"
#include "osrf_prefork.h"
-void __osrfSystemSignalHandler( int sig );
+static int _osrfSystemInitCache( void );
-transport_client* __osrfGlobalTransportClient = NULL;
+static transport_client* osrfGlobalTransportClient = NULL;
-transport_client* osrfSystemGetTransportClient() {
- return __osrfGlobalTransportClient;
+transport_client* osrfSystemGetTransportClient( void ) {
+ return osrfGlobalTransportClient;
}
void osrfSystemIgnoreTransportClient() {
- __osrfGlobalTransportClient = NULL;
+ osrfGlobalTransportClient = NULL;
}
-transport_client* osrf_system_get_transport_client() {
- return __osrfGlobalTransportClient;
+transport_client* osrf_system_get_transport_client( void ) {
+ return osrfGlobalTransportClient;
}
int osrf_system_bootstrap_client( char* config_file, char* contextnode ) {
}
-int _osrfSystemInitCache() {
+static int _osrfSystemInitCache( void ) {
jsonObject* cacheServers = osrf_settings_host_value_object("/cache/global/servers/server");
char* maxCache = osrf_settings_host_value("/cache/global/max_cache_time");
/* first we grab the settings */
if(!osrfSystemBootstrapClientResc(configfile, contextNode, "settings_grabber" )) {
- osrfLogError( OSRF_LOG_MARK, "Unable to bootstrap");
+ osrfLogError( OSRF_LOG_MARK,
+ "Unable to bootstrap for host %s from configuration file %s",
+ hostname, configfile );
return -1;
}
- osrf_settings_retrieve(hostname);
+ int retcode = osrf_settings_retrieve(hostname);
osrf_system_disconnect_client();
+ if( retcode ) {
+ osrfLogError( OSRF_LOG_MARK,
+ "Unable to retrieve settings for host %s from configuration file %s",
+ hostname, configfile );
+ return -1;
+ }
+
jsonObject* apps = osrf_settings_host_value_object("/activeapps/appname");
osrfStringArray* arr = osrfNewStringArray(8);
osrfLogInfo( OSRF_LOG_MARK, "Launching application %s with implementation %s", appname, libfile);
- int pid;
+ pid_t pid;
if( (pid = fork()) ) {
// storage pid in local table for re-launching dead children...
- osrfLogInfo( OSRF_LOG_MARK, "Launched application child %d", pid);
+ osrfLogInfo( OSRF_LOG_MARK, "Launched application child %ld", (long) pid);
} else {
if( osrfAppRegisterApplication( appname, libfile ) == 0 )
osrf_prefork_run(appname);
- osrfLogDebug( OSRF_LOG_MARK, "Server exiting for app %s and library %s", appname, libfile );
+ osrfLogDebug( OSRF_LOG_MARK, "Server exiting for app %s and library %s\n", appname, libfile );
exit(0);
}
} // language == c
/* background and let our children do their thing */
daemonize();
- while(1) {
- signal(SIGCHLD, __osrfSystemSignalHandler);
- sleep(10000);
- }
-
+ while(1) {
+ errno = 0;
+ pid_t pid = wait(NULL);
+ if(-1 == pid) {
+ if(errno == ECHILD)
+ osrfLogError(OSRF_LOG_MARK, "We have no more live services... exiting");
+ else
+ osrfLogError(OSRF_LOG_MARK, "Exiting top-level system loop with error: %s", strerror(errno));
+ break;
+ } else {
+ osrfLogError(OSRF_LOG_MARK, "We lost a top-level service process with PID %ld", pid);
+ }
+ }
+
+
return 0;
}
int osrf_system_bootstrap_client_resc( char* config_file, char* contextnode, char* resource ) {
+ int failure = 0;
+
if(osrfSystemGetTransportClient()) {
osrfLogInfo(OSRF_LOG_MARK, "Client is already bootstrapped");
return 1; /* we already have a client connection */
}
if( config_file ) {
- osrfConfigCleanup();
osrfConfig* cfg = osrfConfigInit( config_file, contextnode );
- osrfConfigSetDefaultConfig(cfg);
+ if(cfg)
+ osrfConfigSetDefaultConfig(cfg);
+ else
+ return 0; /* Can't load configuration? Bail out */
}
char* log_file = osrfConfigGetValue( NULL, "/logfile");
- char* log_level = osrfConfigGetValue( NULL, "/loglevel" );
- osrfStringArray* arr = osrfNewStringArray(8);
+ char* log_level = osrfConfigGetValue( NULL, "/loglevel" );
+ osrfStringArray* arr = osrfNewStringArray(8);
osrfConfigGetValueList(NULL, arr, "/domains/domain");
+
char* username = osrfConfigGetValue( NULL, "/username" );
char* password = osrfConfigGetValue( NULL, "/passwd" );
- char* port = osrfConfigGetValue( NULL, "/port" );
+ char* port = osrfConfigGetValue( NULL, "/port" );
char* unixpath = osrfConfigGetValue( NULL, "/unixpath" );
char* facility = osrfConfigGetValue( NULL, "/syslog" );
char* actlog = osrfConfigGetValue( NULL, "/actlog" );
- char* domain = strdup(osrfStringArrayGetString( arr, 0 )); /* just the first for now */
- osrfStringArrayFree(arr);
+ if(!log_file) {
+ fprintf(stderr, "No log file specified in configuration file %s\n",
+ config_file);
+ free(log_level);
+ free(username);
+ free(password);
+ free(port);
+ free(unixpath);
+ free(facility);
+ free(actlog);
+ return -1;
+ }
- /* if we're a source-client, tell the logger */
- char* isclient = osrfConfigGetValue(NULL, "/client");
- if( isclient && !strcasecmp(isclient,"true") )
- osrfLogSetIsClient(1);
- free(isclient);
+ /* if we're a source-client, tell the logger */
+ char* isclient = osrfConfigGetValue(NULL, "/client");
+ if( isclient && !strcasecmp(isclient,"true") )
+ osrfLogSetIsClient(1);
+ free(isclient);
int llevel = 0;
int iport = 0;
if(port) iport = atoi(port);
if(log_level) llevel = atoi(log_level);
- if(!log_file) { fprintf(stderr, "Log file needed\n"); return -1; }
-
if(!strcmp(log_file, "syslog")) {
osrfLogInit( OSRF_LOG_TYPE_SYSLOG, contextnode, llevel );
osrfLogSetSyslogFacility(osrfLogFacilityToInt(facility));
osrfLogSetFile( log_file );
}
- osrfLogInfo( OSRF_LOG_MARK, "Bootstrapping system with domain %s, port %d, and unixpath %s", domain, iport, unixpath );
+ /* Get a domain, if one is specified */
+ const char* domain = osrfStringArrayGetString( arr, 0 ); /* just the first for now */
+ if(!domain) {
+ fprintf(stderr, "No domain specified in configuration file %s\n", config_file);
+ osrfLogError( OSRF_LOG_MARK, "No domain specified in configuration file %s\n", config_file);
+ failure = 1;
+ }
+
+ if(!username) {
+ fprintf(stderr, "No username specified in configuration file %s\n", config_file);
+ osrfLogError( OSRF_LOG_MARK, "No username specified in configuration file %s\n", config_file);
+ failure = 1;
+ }
+
+ if(!password) {
+ fprintf(stderr, "No password specified in configuration file %s\n", config_file);
+ osrfLogError( OSRF_LOG_MARK, "No password specified in configuration file %s\n", config_file);
+ failure = 1;
+ }
+
+ if((iport <= 0) && !unixpath) {
+ fprintf(stderr, "No unixpath or valid port in configuration file %s\n", config_file);
+ osrfLogError( OSRF_LOG_MARK, "No unixpath or valid port in configuration file %s\n",
+ config_file);
+ failure = 1;
+ }
+
+ if (failure) {
+ osrfStringArrayFree(arr);
+ free(log_level);
+ free(username);
+ free(password);
+ free(port);
+ free(unixpath);
+ free(facility);
+ free(actlog);
+ return 0;
+ }
+
+ osrfLogInfo( OSRF_LOG_MARK, "Bootstrapping system with domain %s, port %d, and unixpath %s",
+ domain, iport, unixpath ? unixpath : "(none)" );
transport_client* client = client_init( domain, iport, unixpath, 0 );
- char* host;
+ const char* host;
host = getenv("HOSTNAME");
char tbuf[32];
- memset(tbuf, 0x0, 32);
+ tbuf[0] = '\0';
snprintf(tbuf, 32, "%f", get_timestamp_millis());
if(!host) host = "";
int len = strlen(resource) + 256;
char buf[len];
- memset(buf,0,len);
- snprintf(buf, len - 1, "%s_%s_%s_%d", resource, host, tbuf, getpid() );
-
+ buf[0] = '\0';
+ snprintf(buf, len - 1, "%s_%s_%s_%ld", resource, host, tbuf, (long) getpid() );
+
if(client_connect( client, username, password, buf, 10, AUTH_DIGEST )) {
/* child nodes will leak the parents client... but we can't free
it without disconnecting the parents client :( */
- __osrfGlobalTransportClient = client;
+ osrfGlobalTransportClient = client;
}
+ osrfStringArrayFree(arr);
free(actlog);
free(facility);
free(log_level);
free(password);
free(port);
free(unixpath);
- free(domain);
- if(__osrfGlobalTransportClient)
+ if(osrfGlobalTransportClient)
return 1;
return 0;
}
-int osrf_system_disconnect_client() {
- client_disconnect( __osrfGlobalTransportClient );
- client_free( __osrfGlobalTransportClient );
- __osrfGlobalTransportClient = NULL;
+int osrf_system_disconnect_client( void ) {
+ client_disconnect( osrfGlobalTransportClient );
+ client_free( osrfGlobalTransportClient );
+ osrfGlobalTransportClient = NULL;
return 0;
}
-int osrf_system_shutdown() {
+int osrf_system_shutdown( void ) {
osrfConfigCleanup();
osrf_system_disconnect_client();
osrf_settings_free_host_config(NULL);
-void __osrfSystemSignalHandler( int sig ) {
-
- pid_t pid;
- int status;
-
- while( (pid = waitpid(-1, &status, WNOHANG)) > 0) {
- osrfLogWarning( OSRF_LOG_MARK, "We lost child %d", pid);
- }
-
- /** relaunch the server **/
-}
-
-
*/
int osrfSystemBootstrap( char* hostName, char* configfile, char* contextNode );
-transport_client* osrfSystemGetTransportClient();
-transport_client* osrf_system_get_transport_client();
+transport_client* osrfSystemGetTransportClient( void );
+transport_client* osrf_system_get_transport_client( void );
/* disconnects and destroys the current client connection */
int osrf_system_disconnect_client();
-int osrf_system_shutdown();
-
-int _osrfSystemInitCache();
+int osrf_system_shutdown( void );
/* this will clear the global transport client pointer without
if( (pid=fork()) ) { /* parent */
signal(SIGINT, sig_int);
- fprintf(stderr, "Listener: %d\n", getpid() );
+ fprintf(stderr, "Listener: %ld\n", (long) getpid() );
char buf[300];
memset(buf, 0, 300);
printf("=> ");
} else {
- fprintf(stderr, "Sender: %d\n", getpid() );
+ fprintf(stderr, "Sender: %ld\n", (long) getpid() );
transport_message* recv;
while( (recv=client_recv( client, -1)) ) {
*/
-transport_client* client_init( char* server, int port, char* unix_path, int component ) {
+transport_client* client_init( const char* server, int port, const char* unix_path, int component ) {
if(server == NULL) return NULL;
/* build and clear the client object */
size_t c_size = sizeof( transport_client);
- transport_client* client = (transport_client*) safe_malloc( c_size );
+ transport_client* client = safe_malloc( c_size );
/* build and clear the message list */
size_t l_size = sizeof( transport_message_list );
- client->m_list = (transport_message_list*) safe_malloc( l_size );
+ client->m_list = safe_malloc( l_size );
+ client->m_list->next = NULL;
+ client->m_list->message = NULL;
client->m_list->type = MESSAGE_LIST_HEAD;
+
+ /* build the session */
+
client->session = init_transport( server, port, unix_path, client, component );
client->session->message_callback = client_message_handler;
// if port > 0 => connect via TCP
// else if unix_path != NULL => connect via UNIX socket
// ---------------------------------------------------------------------------
-transport_client* client_init( char* server, int port, char* unix_path, int component );
+transport_client* client_init( const char* server, int port, const char* unix_path, int component );
// ---------------------------------------------------------------------------
// returns a built and allocated transport_session object.
// This codes does no network activity, only memory initilization
// ---------------------------------------------------------------------------------
-transport_session* init_transport( char* server,
- int port, char* unix_path, void* user_data, int component ) {
+transport_session* init_transport( const char* server,
+ int port, const char* unix_path, void* user_data, int component ) {
/* create the session struct */
transport_session* session =
int ret = socket_wait( session->sock_mgr, timeout, session->sock_id );
if( ret ) {
- osrfLogWarning(OSRF_LOG_MARK, "socket_wait returned error code %d", ret);
+ osrfLogDebug(OSRF_LOG_MARK, "socket_wait returned error code %d", ret);
session->state_machine->connected = 0;
}
return ret;
session->sock_mgr, session->unix_path)) <= 0 )
return 0;
}
+ else {
+ osrfLogWarning( OSRF_LOG_MARK, "Can't open session: no port or unix path" );
+ return 0;
+ }
}
if( session->component ) {
// If port > 0, then this session uses TCP connection. Otherwise,
// if unix_path != NULL, it uses a UNIX domain socket.
// ------------------------------------------------------------------
-transport_session* init_transport( char* server, int port,
- char* unix_path, void* user_data, int component );
+transport_session* init_transport( const char* server, int port,
+ const char* unix_path, void* user_data, int component );
// ------------------------------------------------------------------
// Returns the value of the given XML attribute
/* the JSON parser, so we can read the response we're XMLizing */
#include "object.h"
#include "json_parser.h"
-#include "utils.h"
+#include "opensrf/utils.h"
char* jsonObjectToXML(jsonObject*);
#include <stdio.h>
#include "object.h"
-#include "utils.h"
+#include "opensrf/utils.h"
#include <stdlib.h>
#include <string.h>
-#include "utils.h"
+#include "opensrf/utils.h"
/* json object types */
#define JSON_HASH 0
}
my ($protokey,$value,$keytype,$key);
- if ($line =~ /^([^=\s]+)\s*=\s*(.*)/s) {
+ if ($line =~ /^([^=\s]+)\s*=\s*(.*)\s*$/s) {
($protokey,$value) = ($1,$2);
($keytype,$key) = split(/:/,$protokey);
}
=head1 BUGS
-No know bugs, but report any to miker@purplefrog.com.
+No know bugs, but report any to mrylander@gmail.com.
=head1 COPYRIGHT AND LICENSING
-Mike Rylander, Copyright 2000-2004
+Mike Rylander, Copyright 2000-2007
The OpenSRF::Utils::Config module is free software. You may distribute under the terms
of the GNU General Public License version 2 or greater.
--- /dev/null
+# OSRF_LOG_PARAMS log all incoming method params at OSRF_INFO log level.
+# OSRF_STRICT_PARAMS instructs the app handler to return an error if the number of method arguments
+# provided to any method is not at least as large as the 'argc' setting for the method
+
+CFLAGS += -rdynamic -fno-strict-aliasing -fPIC
+
+TARGETS = strndup.o strnlen.o
+HEADERS = strndup.h strnlen.h
+
+all: libfreebsd_str_compat.so $(TARGETS)
+
+libfreebsd_str_compat.so: $(TARGETS)
+ $(CC) -shared -W1 $(TARGETS) -o $@
+
+strndup.o: strndup.c strndup.h
+strnlen.o: strnlen.c strnlen.h
+
+clean:
+ /bin/rm -f *o
+
--- /dev/null
+/*
+ * Copyright (c) 2007 Albert Lee <trisk at acm.jhu.edu>.
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#include <stdlib.h>
+#include <string.h>
+
+#include "strnlen.h"
+
+char *
+strndup(const char *s, size_t n)
+{
+ char *ns;
+
+ n = strnlen(s, n);
+
+ if ((ns = (char *)malloc(n + 1))) {
+ ns[n] = '\0';
+ return memcpy(ns, s, n);
+ }
+
+ return NULL;
+}
--- /dev/null
+/*
+ * Copyright (c) 2007 Albert Lee <trisk at acm.jhu.edu>.
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+char *strndup(const char *s, size_t n);
+
--- /dev/null
+/*
+ * Copyright (c) 2007 The Akuma Project
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ *
+ * $Id$
+ */
+
+/*
+ * sys/types.h is a Single Unix Specification header and defines size_t.
+ */
+
+#include <sys/types.h>
+
+/*
+ * As per the Linux manual page:
+ *
+ * The strnlen() function returns the number of characters in the string
+ * pointed to by s, not including the terminating '\0' character, but at most
+ * maxlen. In doing this, strnlen() looks only at the first maxlen characters
+ * at s and never beyond s+maxlen.
+ *
+ * The strnlen() function returns strlen(s), if that is less than maxlen, or
+ * maxlen if there is no '\0' character among the first maxlen characters
+ * pointed to by s.
+ */
+
+size_t
+strnlen(const char *string, size_t maxlen)
+{
+ int len = 0;
+
+ if (maxlen == 0)
+ return (0);
+
+ while (*string++ && ++len < maxlen)
+ ;
+
+ return (len);
+}
--- /dev/null
+/*
+ * Copyright (c) 2007 The Akuma Project
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ *
+ * $Id$
+ */
+
+size_t strnlen(const char *, size_t);
+
--- /dev/null
+from xml.dom import minidom
+from xml.sax import handler, make_parser, saxutils
+from json import *
+from net_obj import *
+import urllib, urllib2, sys
+
+defaultHost = None
+
+class GatewayRequest:
+ def __init__(self, service, method, params=[]):
+ self.service = service
+ self.method = method
+ self.params = params
+
+ def send(self):
+ params = self.buildPOSTParams()
+ request = urllib2.Request(self.buildURL(), data=params)
+ response = None
+ try:
+ response =urllib2.urlopen(request)
+ except urllib2.HTTPError, e:
+ # log this?
+ sys.stderr.write('HTTPError: code=%d : %s' % (e.code, str(e)))
+ raise e
+
+ return self.handleResponse(response)
+
+ def buildPOSTParams(self):
+
+ params = urllib.urlencode({
+ 'service': self.service,
+ 'method': self.method,
+ 'format': self.getFormat()
+ })
+
+ for p in self.params:
+ param = {'param': osrfObjectToJSON(p)}
+ params += '&%s' % urllib.urlencode(param)
+
+ return params
+
+ def setDefaultHost(host):
+ global defaultHost
+ defaultHost = host
+ setDefaultHost = staticmethod(setDefaultHost)
+
+ def buildURL(self):
+ return 'http://%s/gateway' % defaultHost
+
+
+class XMLGatewayRequest(GatewayRequest):
+
+ def __init__(self, service, method, *params):
+ GatewayRequest.__init__(self, service, method, list(params))
+
+ def getFormat(self):
+ return 'xml'
+
+ def handleResponse(self, response):
+ handler = XMLGatewayParser()
+ parser = make_parser()
+ parser.setContentHandler(handler)
+ parser.parse(response)
+ return handler.getResult()
+
+class XMLGatewayParser(handler.ContentHandler):
+
+ def __init__(self):
+ self.result = None
+ self.objStack = []
+ self.keyStack = []
+
+ def getResult(self):
+ return self.result
+
+ def __getAttr(self, attrs, name):
+ for (k, v) in attrs.items():
+ if k == name:
+ return v
+ return None
+
+ def startElement(self, name, attrs):
+
+ # XXX add support for serializable objects!
+
+ if name == 'element': # this is an object item wrapper
+ self.keyStack.append(self.__getAttr(attrs, 'key'))
+ return
+
+ if name == 'object':
+ obj = {}
+ self.appendChild(obj)
+ self.objStack.append(obj)
+ return
+
+ if name == 'array':
+ obj = []
+ self.appendChild(obj)
+ self.objStack.append(obj)
+ return
+
+ if name == 'null':
+ self.appendChild(None)
+ return
+
+ if name == 'boolean':
+ self.appendChild((self.__getAttr(attrs, 'value') == 'true'))
+ return
+
+
+ def appendChild(self, child):
+
+ if self.result == None:
+ self.result = child
+
+ if not self.objStack: return;
+
+ parent = self.objStack[len(self.objStack)-1]
+
+ if( isinstance(parent, list) ):
+ parent.append(child)
+ else:
+ parent[self.keyStack.pop()] = child
+
+ def endElement(self, name):
+ if name == 'array' or name == 'object':
+ self.objStack.pop()
+
+ def characters(self, chars):
+ #self.appendChild(''.join(chars[start:leng+start]))
+ self.appendChild(urllib.unquote_plus(chars))
+
+
+
+
+
# -----------------------------------------------------------------------
-import simplejson, types, cjson
+import simplejson, types
+from osrf.net_obj import *
JSON_PAYLOAD_KEY = '__p'
JSON_CLASS_KEY = '__c'
-class osrfNetworkObject(object):
- """Base class for serializable network objects."""
- def getData(self):
- """Returns a dict of data contained by this object"""
- return self.data
-
-
-class __unknown(osrfNetworkObject):
- """Default class for un-registered network objects."""
- def __init__(self, data=None):
- self.data = data
-
-setattr(__unknown,'__keys', [])
-setattr(osrfNetworkObject,'__unknown', __unknown)
-
-
-def osrfNetworkRegisterHint(hint, keys, type='hash'):
- """Register a network hint.
-
- This creates a new class at osrfNetworkObject.<hint> with
- methods for accessing/mutating the object's data.
- Method names will match the names found in the keys array
-
- hint - The hint name to encode with the object
- type - The data container type.
- keys - An array of data keys. If type is an 'array', the order of
- the keys will determine how the data is accessed
- """
-
- # XXX there must be a cleaner way to do this via the python API
-
- estr = "class %s(osrfNetworkObject):\n" % hint
- estr += "\tdef __init__(self, data=None):\n"
- estr += "\t\tself.data = data\n"
- estr += "\t\tif data:\n"
-
- if type == 'hash':
- estr += "\t\t\tpass\n"
- else:
- # we have to make sure the array is large enough
- estr += "\t\t\twhile len(data) < %d:\n" % len(keys)
- estr += "\t\t\t\tdata.append(None)\n"
-
- estr += "\t\telse:\n"
-
- if type == 'array':
- estr += "\t\t\tself.data = []\n"
- estr += "\t\t\tfor i in range(%s):\n" % len(keys)
- estr += "\t\t\t\tself.data.append(None)\n"
- for i in range(len(keys)):
- estr += "\tdef %s(self, *args):\n"\
- "\t\tif len(args) != 0:\n"\
- "\t\t\tself.data[%s] = args[0]\n"\
- "\t\treturn self.data[%s]\n" % (keys[i], i, i)
-
- if type == 'hash':
- estr += "\t\t\tself.data = {}\n"
- estr += "\t\t\tfor i in %s:\n" % str(keys)
- estr += "\t\t\t\tself.data[i] = None\n"
- for i in keys:
- estr += "\tdef %s(self, *args):\n"\
- "\t\tif len(args) != 0:\n"\
- "\t\t\tself.data['%s'] = args[0]\n"\
- "\t\tval = None\n"\
- "\t\ttry: val = self.data['%s']\n"\
- "\t\texcept: return None\n"\
- "\t\treturn val\n" % (i, i, i)
-
- estr += "setattr(osrfNetworkObject, '%s', %s)\n" % (hint,hint)
- estr += "setattr(osrfNetworkObject.%s, '__keys', keys)" % hint
- exec(estr)
-
-
-
-# -------------------------------------------------------------------
-# Define the custom object parsing behavior
-# -------------------------------------------------------------------
-def __parseNetObject(obj):
- hint = None
- #islist = False
- try:
- hint = obj[JSON_CLASS_KEY]
- obj = obj[JSON_PAYLOAD_KEY]
- except: pass
- if isinstance(obj,list):
- #islist = True
- for i in range(len(obj)):
- obj[i] = __parseNetObject(obj[i])
- else:
- if isinstance(obj,dict):
- for k,v in obj.iteritems():
- obj[k] = __parseNetObject(v)
-
- if hint: # Now, "bless" the object into an osrfNetworkObject
- estr = 'obj = osrfNetworkObject.%s(obj)' % hint
- try:
- exec(estr)
- except AttributeError:
- # this object has not been registered, shove it into the default container
- obj = osrfNetworkObject.__unknown(obj)
-
- return obj;
-
-
-# -------------------------------------------------------------------
+#class osrfNetworkObject(object):
+# """Base class for serializable network objects."""
+# def getData(self):
+# """Returns a dict of data contained by this object"""
+# return self.data
+#
+#
+#class __unknown(osrfNetworkObject):
+# """Default class for un-registered network objects."""
+# def __init__(self, data=None):
+# self.data = data
+#
+#setattr(__unknown,'__keys', [])
+#setattr(osrfNetworkObject,'__unknown', __unknown)
+#
+#
+#def osrfNetworkRegisterHint(hint, keys, type='hash'):
+# """Register a network hint.
+#
+# This creates a new class at osrfNetworkObject.<hint> with
+# methods for accessing/mutating the object's data.
+# Method names will match the names found in the keys array
+#
+# hint - The hint name to encode with the object
+# type - The data container type.
+# keys - An array of data keys. If type is an 'array', the order of
+# the keys will determine how the data is accessed
+# """
+#
+# estr = "class %s(osrfNetworkObject):\n" % hint
+# estr += "\tdef __init__(self, data=None):\n"
+# estr += "\t\tself.data = data\n"
+# estr += "\t\tif data:\n"
+#
+# if type == 'hash':
+# estr += "\t\t\tpass\n"
+# else:
+# # we have to make sure the array is large enough
+# estr += "\t\t\twhile len(data) < %d:\n" % len(keys)
+# estr += "\t\t\t\tdata.append(None)\n"
+#
+# estr += "\t\telse:\n"
+#
+# if type == 'array':
+# estr += "\t\t\tself.data = []\n"
+# estr += "\t\t\tfor i in range(%s):\n" % len(keys)
+# estr += "\t\t\t\tself.data.append(None)\n"
+# for i in range(len(keys)):
+# estr += "\tdef %s(self, *args):\n"\
+# "\t\tif len(args) != 0:\n"\
+# "\t\t\tself.data[%s] = args[0]\n"\
+# "\t\treturn self.data[%s]\n" % (keys[i], i, i)
+#
+# if type == 'hash':
+# estr += "\t\t\tself.data = {}\n"
+# estr += "\t\t\tfor i in %s:\n" % str(keys)
+# estr += "\t\t\t\tself.data[i] = None\n"
+# for i in keys:
+# estr += "\tdef %s(self, *args):\n"\
+# "\t\tif len(args) != 0:\n"\
+# "\t\t\tself.data['%s'] = args[0]\n"\
+# "\t\tval = None\n"\
+# "\t\ttry: val = self.data['%s']\n"\
+# "\t\texcept: return None\n"\
+# "\t\treturn val\n" % (i, i, i)
+#
+# estr += "setattr(osrfNetworkObject, '%s', %s)\n" % (hint,hint)
+# estr += "setattr(osrfNetworkObject.%s, '__keys', keys)" % hint
+# exec(estr)
+#
+#
+#
+## -------------------------------------------------------------------
+## Define the custom object parsing behavior
+## -------------------------------------------------------------------
+#def __parseNetObject(obj):
+# hint = None
+# islist = False
+# try:
+# hint = obj[JSON_CLASS_KEY]
+# obj = obj[JSON_PAYLOAD_KEY]
+# except: pass
+# if isinstance(obj,list):
+# islist = True
+# for i in range(len(obj)):
+# obj[i] = __parseNetObject(obj[i])
+# else:
+# if isinstance(obj,dict):
+# for k,v in obj.iteritems():
+# obj[k] = __parseNetObject(v)
+#
+# if hint: # Now, "bless" the object into an osrfNetworkObject
+# estr = 'obj = osrfNetworkObject.%s(obj)' % hint
+# try:
+# exec(estr)
+# except AttributeError:
+# # this object has not been registered, shove it into the default container
+# obj = osrfNetworkObject.__unknown(obj)
+#
+# return obj;
+#
+#
+## -------------------------------------------------------------------
# Define the custom object encoding behavior
# -------------------------------------------------------------------
+
class osrfJSONNetworkEncoder(simplejson.JSONEncoder):
- def default(self, obj):
- if isinstance(obj, osrfNetworkObject):
- return {
- JSON_CLASS_KEY: obj.__class__.__name__,
- JSON_PAYLOAD_KEY: self.default(obj.getData())
- }
- return obj
+ def default(self, obj):
+ if isinstance(obj, osrfNetworkObject):
+ return {
+ JSON_CLASS_KEY: obj.__class__.__name__,
+ JSON_PAYLOAD_KEY: self.default(obj.getData())
+ }
+ return obj
def osrfObjectToJSON(obj):
- """Turns a python object into a wrapped JSON object"""
- return simplejson.dumps(obj, cls=osrfJSONNetworkEncoder)
+ """Turns a python object into a wrapped JSON object"""
+ return simplejson.dumps(obj, cls=osrfJSONNetworkEncoder)
def osrfJSONToObject(json):
- """Turns a JSON string into python objects"""
- #obj = simplejson.loads(json)
- obj = None
- try:
- obj = cjson.decode(json)
- except Exception:
- # cjson is more finicky, if it dies, try simplejson
- obj = simplejson.loads(json)
- return __parseNetObject(obj)
+ """Turns a JSON string into python objects"""
+ obj = simplejson.loads(json)
+ return parseNetObject(obj)
def osrfParseJSONRaw(json):
- """Parses JSON the old fashioned way."""
- return simplejson.loads(json)
+ """Parses JSON the old fashioned way."""
+ return simplejson.loads(json)
def osrfToJSONRaw(obj):
- """Stringifies an object as JSON with no additional logic."""
- return simplejson.dumps(obj)
+ """Stringifies an object as JSON with no additional logic."""
+ return simplejson.dumps(obj)
def __tabs(t):
- r=''
- for i in range(t): r += ' '
- return r
+ r=''
+ for i in range(t): r += ' '
+ return r
-def osrfDebugNetworkObject(obj, t=0):
- """Returns a debug string for a given object.
+def osrfDebugNetworkObject(obj, t=1):
+ """Returns a debug string for a given object.
- If it's an osrfNetworkObject and has registered keys, key/value p
- pairs are returned. Otherwise formatted JSON is returned"""
+ If it's an osrfNetworkObject and has registered keys, key/value p
+ pairs are returned. Otherwise formatted JSON is returned"""
- s = ''
- if isinstance(obj, osrfNetworkObject) and len(obj.__keys):
- obj.__keys.sort()
+ s = ''
+ if isinstance(obj, osrfNetworkObject) and len(obj.__keys):
+ obj.__keys.sort()
- for k in obj.__keys:
+ for k in obj.__keys:
- key = k
- while len(key) < 24: key += '.' # pad the names to make the values line up somewhat
- val = getattr(obj, k)()
+ key = k
+ while len(key) < 24: key += '.' # pad the names to make the values line up somewhat
+ val = getattr(obj, k)()
- subobj = val and not (isinstance(val,unicode) or isinstance(val,str) or\
- isinstance(val, int) or isinstance(val, float) or isinstance(val, long))
+ subobj = val and not (isinstance(val,unicode) or \
+ isinstance(val, int) or isinstance(val, float) or isinstance(val, long))
- s += __tabs(t) + key + ' '
+ s += __tabs(t) + key + ' = '
- if subobj:
- s += '\n'
- val = osrfDebugNetworkObject(val, t+1)
+ if subobj:
+ s += '\n'
+ val = osrfDebugNetworkObject(val, t+1)
- s += str(val)
+ s += str(val)
- if not subobj: s += '\n'
+ if not subobj: s += '\n'
- else:
- s = osrfFormatJSON(osrfObjectToJSON(obj))
- return s
+ else:
+ s = osrfFormatJSON(osrfObjectToJSON(obj))
+ return s
def osrfFormatJSON(json):
- """JSON pretty-printer"""
- r = ''
- t = 0
- instring = False
- inescape = False
- done = False
+ """JSON pretty-printer"""
+ r = ''
+ t = 0
+ instring = False
+ inescape = False
+ done = False
- for c in json:
+ for c in json:
- done = False
- if (c == '{' or c == '[') and not instring:
- t += 1
- r += c + '\n' + __tabs(t)
- done = True
+ done = False
+ if (c == '{' or c == '[') and not instring:
+ t += 1
+ r += c + '\n' + __tabs(t)
+ done = True
- if (c == '}' or c == ']') and not instring:
- t -= 1
- r += '\n' + __tabs(t) + c
- done = True
+ if (c == '}' or c == ']') and not instring:
+ t -= 1
+ r += '\n' + __tabs(t) + c
+ done = True
- if c == ',' and not instring:
- r += c + '\n' + __tabs(t)
- done = True
+ if c == ',' and not instring:
+ r += c + '\n' + __tabs(t)
+ done = True
- if c == '"' and not inescape:
- instring = not instring
+ if c == '"' and not inescape:
+ instring = not instring
- if inescape:
- inescape = False
+ if inescape:
+ inescape = False
- if c == '\\':
- inescape = True
+ if c == '\\':
+ inescape = True
- if not done:
- r += c
+ if not done:
+ r += c
- return r
+ return r
-
+
--- /dev/null
+# -----------------------------------------------------------------------
+# Copyright (C) 2007 Georgia Public Library Service
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+# -----------------------------------------------------------------------
+
+
+JSON_PAYLOAD_KEY = '__p'
+JSON_CLASS_KEY = '__c'
+
+class osrfNetworkObject(object):
+ """Base class for serializable network objects."""
+ def getData(self):
+ """Returns a dict of data contained by this object"""
+ return self.data
+
+
+class __unknown(osrfNetworkObject):
+ """Default class for un-registered network objects."""
+ def __init__(self, data=None):
+ self.data = data
+
+setattr(__unknown,'__keys', [])
+setattr(osrfNetworkObject,'__unknown', __unknown)
+
+
+def osrfNetworkRegisterHint(hint, keys, type='hash'):
+ """Register a network hint.
+
+ This creates a new class at osrfNetworkObject.<hint> with
+ methods for accessing/mutating the object's data.
+ Method names will match the names found in the keys array
+
+ hint - The hint name to encode with the object
+ type - The data container type.
+ keys - An array of data keys. If type is an 'array', the order of
+ the keys will determine how the data is accessed
+ """
+
+ #
+ # XXX Surely there is a cleaner way to accomplish this via
+ # the PythonAPI
+ #
+
+ estr = "class %s(osrfNetworkObject):\n" % hint
+ estr += "\tdef __init__(self, data=None):\n"
+ estr += "\t\tself.data = data\n"
+ estr += "\t\tif data:\n"
+
+ if type == 'hash':
+ estr += "\t\t\tpass\n"
+ else:
+ # we have to make sure the array is large enough
+ estr += "\t\t\twhile len(data) < %d:\n" % len(keys)
+ estr += "\t\t\t\tdata.append(None)\n"
+
+ estr += "\t\telse:\n"
+
+ if type == 'array':
+ estr += "\t\t\tself.data = []\n"
+ estr += "\t\t\tfor i in range(%s):\n" % len(keys)
+ estr += "\t\t\t\tself.data.append(None)\n"
+ for i in range(len(keys)):
+ estr += "\tdef %s(self, *args):\n"\
+ "\t\tif len(args) != 0:\n"\
+ "\t\t\tself.data[%s] = args[0]\n"\
+ "\t\treturn self.data[%s]\n" % (keys[i], i, i)
+
+ if type == 'hash':
+ estr += "\t\t\tself.data = {}\n"
+ estr += "\t\t\tfor i in %s:\n" % str(keys)
+ estr += "\t\t\t\tself.data[i] = None\n"
+ for i in keys:
+ estr += "\tdef %s(self, *args):\n"\
+ "\t\tif len(args) != 0:\n"\
+ "\t\t\tself.data['%s'] = args[0]\n"\
+ "\t\tval = None\n"\
+ "\t\ttry: val = self.data['%s']\n"\
+ "\t\texcept: return None\n"\
+ "\t\treturn val\n" % (i, i, i)
+
+ estr += "setattr(osrfNetworkObject, '%s', %s)\n" % (hint,hint)
+ estr += "setattr(osrfNetworkObject.%s, '__keys', keys)" % hint
+ exec(estr)
+
+
+
+# -------------------------------------------------------------------
+# Define the custom object parsing behavior
+# -------------------------------------------------------------------
+def parseNetObject(obj):
+ hint = None
+ islist = False
+ try:
+ hint = obj[JSON_CLASS_KEY]
+ obj = obj[JSON_PAYLOAD_KEY]
+ except: pass
+ if isinstance(obj,list):
+ islist = True
+ for i in range(len(obj)):
+ obj[i] = parseNetObject(obj[i])
+ else:
+ if isinstance(obj,dict):
+ for k,v in obj.iteritems():
+ obj[k] = parseNetObject(v)
+
+ if hint: # Now, "bless" the object into an osrfNetworkObject
+ estr = 'obj = osrfNetworkObject.%s(obj)' % hint
+ try:
+ exec(estr)
+ except AttributeError:
+ # this object has not been registered, shove it into the default container
+ obj = osrfNetworkObject.__unknown(obj)
+
+ return obj;
+
+
+
+
# -----------------------------------------------------------------------
from osrf.json import *
+from osrf.net_obj import *
from osrf.conf import osrfConfigValue
from osrf.net import osrfNetworkMessage, osrfGetNetworkHandle
from osrf.log import *
-# -----------------------------------------------------------------------
-# Copyright (C) 2007 Georgia Public Library Service
-# Bill Erickson <billserickson@gmail.com>
-#
-# This program is free software; you can redistribute it and/or
-# modify it under the terms of the GNU General Public License
-# as published by the Free Software Foundation; either version 2
-# of the License, or (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-# -----------------------------------------------------------------------
-
-import libxml2, re
+import xml.dom.minidom, re
def osrfXMLFileToObject(filename):
- """Turns the contents of an XML file into a Python object"""
- doc = libxml2.parseFile(filename)
- xmlNode = doc.children.children
- return osrfXMLNodeToObject(xmlNode)
+ """Turns the contents of an XML file into a Python object"""
+ doc = xml.dom.minidom.parse(filename)
+ obj = osrfXMLNodeToObject(doc.childNodes[0])
+ doc.unlink()
+ return obj
def osrfXMLStringToObject(string):
- """Turns an XML string into a Python object"""
- doc = libxml2.parseString(string)
- xmlNode = doc.children.children
- return osrfXMLNodeToObject(xmlNode)
+ """Turns an XML string into a Python object"""
+ doc = xml.dom.minidom.parseString(string)
+ obj = osrfXMLNodeToObject(doc.childNodes[0])
+ doc.unlink()
+ return obj
def osrfXMLNodeToObject(xmlNode):
- """Turns an XML node into a Python object"""
- obj = {}
+ """Turns an XML node into a Python object"""
+ obj = {}
- while xmlNode:
- if xmlNode.type == 'element':
- nodeChild = xmlNode.children
- done = False
- nodeName = xmlNode.name
+ if xmlNode.nodeType != xmlNode.ELEMENT_NODE:
+ return obj
- while nodeChild:
- if nodeChild.type == 'element':
+ done = False
+ nodeName = xmlNode.nodeName
- # If a node has element children, create a new sub-object
- # for this node, attach an array for each type of child
- # and recursively collect the children data into the array(s)
+ for nodeChild in xmlNode.childNodes:
+ if nodeChild.nodeType == xmlNode.ELEMENT_NODE:
- if not obj.has_key(nodeName):
- obj[nodeName] = {}
+ # If a node has element children, create a new sub-object
+ # for this node, attach an array for each type of child
+ # and recursively collect the children data into the array(s)
- sub_obj = osrfXMLNodeToObject(nodeChild);
+ if not obj.has_key(nodeName):
+ obj[nodeName] = {}
- if not obj[nodeName].has_key(nodeChild.name):
- # we've encountered 1 sub-node with nodeChild's name
- obj[nodeName][nodeChild.name] = sub_obj[nodeChild.name]
+ sub_obj = osrfXMLNodeToObject(nodeChild);
- else:
- if isinstance(obj[nodeName][nodeChild.name], list):
- # we already have multiple sub-nodes with nodeChild's name
- obj[nodeName][nodeChild.name].append(sub_obj[nodeChild.name])
+ if not obj[nodeName].has_key(nodeChild.nodeName):
+ # we've encountered 1 sub-node with nodeChild's name
+ obj[nodeName][nodeChild.nodeName] = sub_obj[nodeChild.nodeName]
- else:
- # we already have 1 sub-node with nodeChild's name, make
- # it a list and append the current node
- val = obj[nodeName][nodeChild.name]
- obj[nodeName][nodeChild.name] = [ val, sub_obj[nodeChild.name] ]
+ else:
+ if isinstance(obj[nodeName][nodeChild.nodeName], list):
+ # we already have multiple sub-nodes with nodeChild's name
+ obj[nodeName][nodeChild.nodeName].append(sub_obj[nodeChild.nodeName])
- done = True
+ else:
+ # we already have 1 sub-node with nodeChild's name, make
+ # it a list and append the current node
+ val = obj[nodeName][nodeChild.nodeName]
+ obj[nodeName][nodeChild.nodeName] = [ val, sub_obj[nodeChild.nodeName] ]
- nodeChild = nodeChild.next
+ done = True
- if not done:
- # If the node has no children, clean up the text content
- # and use that as the data
- data = re.compile('^\s*').sub('', xmlNode.content)
- data = re.compile('\s*$').sub('', data)
+ if not done:
+ # If the node has no element children, clean up the text content
+ # and use that as the data
+ xmlNode = xmlNode.childNodes[0] # extract the text node
+ data = re.compile('^\s*').sub('', str(xmlNode.nodeValue))
+ data = re.compile('\s*$').sub('', data)
- obj[nodeName] = data
+ obj[nodeName] = data
- xmlNode = xmlNode.next
-
- return obj
+ return obj
def osrfObjectFindPath(obj, path, idx=None):
- """Searches an object along the given path for a value to return.
+ """Searches an object along the given path for a value to return.
- Path separaters can be '/' or '.', '/' is tried first."""
+ Path separaters can be '/' or '.', '/' is tried first."""
- parts = []
+ parts = []
- if re.compile('/').search(path):
- parts = path.split('/')
- else:
- parts = path.split('.')
+ if re.compile('/').search(path):
+ parts = path.split('/')
+ else:
+ parts = path.split('.')
- for part in parts:
- try:
- o = obj[part]
- except Exception:
- return None
- if isinstance(o,str):
- return o
- if isinstance(o,list):
- if( idx != None ):
- return o[idx]
- return o
- if isinstance(o,dict):
- obj = o
- else:
- return o
+ for part in parts:
+ try:
+ o = obj[part]
+ except Exception:
+ return None
+ if isinstance(o,str):
+ return o
+ if isinstance(o,list):
+ if( idx != None ):
+ return o[idx]
+ return o
+ if isinstance(o,dict):
+ obj = o
+ else:
+ return o
- return obj
+ return obj
-
+
/* go ahead and create the xid prefix so it will be consistent later */
static char buff[32];
memset(buff, 0x0, 32);
- snprintf(buff, 32, "%d%d", (int)time(NULL), getpid());
+ snprintf(buff, 32, "%d%ld", (int)time(NULL), (long) getpid());
__osrfLogXidPfx = buff;
}
buf[1533] = '.';
buf[1534] = '.';
buf[1535] = '\0';
- syslog( fac | lvl, "[%s:%d:%s:%d:%s] %s", l, getpid(), filename, line, xid, buf );
+ syslog( fac | lvl, "[%s:%ld:%s:%d:%s] %s", l, (long) getpid(), filename, line, xid, buf );
}
else if( __osrfLogType == OSRF_LOG_TYPE_FILE )
- _osrfLogToFile("[%s:%d:%s:%d:%s] %s", l, getpid(), filename, line, xid, msg );
+ _osrfLogToFile("[%s:%ld:%s:%d:%s] %s", l, (long) getpid(), filename, line, xid, msg );
}
FILE* file = fopen(__osrfLogFile, "a");
if(!file) {
- fprintf(stderr, "Unable to fopen file %s for writing", __osrfLogFile);
+ fprintf(stderr, "Unable to fopen file %s for writing\n", __osrfLogFile);
return;
}
fprintf(file, "%s %s %s\n", __osrfLogAppname, datebuf, VA_BUF );
if( fclose(file) != 0 )
osrfLogWarning(OSRF_LOG_MARK, "Error closing log file: %s", strerror(errno));
-
+
}
#include "socket_bundle.h"
+/* buffer used to read from the sockets */
+#define RBUFSIZE 1024
+
+static socket_node* _socket_add_node(socket_manager* mgr,
+ int endpoint, int addr_type, int sock_fd, int parent_id );
+static socket_node* socket_find_node(socket_manager* mgr, int sock_fd);
+static void socket_remove_node(socket_manager*, int sock_fd);
+static int _socket_send(int sock_fd, const char* data, int flags);
+static int _socket_route_data(socket_manager* mgr, int num_active, fd_set* read_set);
+static int _socket_route_data_id( socket_manager* mgr, int sock_id);
+static int _socket_handle_new_client(socket_manager* mgr, socket_node* node);
+static int _socket_handle_client_data(socket_manager* mgr, socket_node* node);
+
+
/* --------------------------------------------------------------------
Test Code
-------------------------------------------------------------------- */
/* -------------------------------------------------------------------- */
-
-socket_node* _socket_add_node(socket_manager* mgr,
+/* allocates and inserts a new socket node into the nodeset.
+ if parent_id is positive and non-zero, it will be set */
+static socket_node* _socket_add_node(socket_manager* mgr,
int endpoint, int addr_type, int sock_fd, int parent_id ) {
if(mgr == NULL) return NULL;
int sock_fd;
struct sockaddr_in server_addr;
+ errno = 0;
sock_fd = socket(AF_INET, SOCK_STREAM, 0);
-
if(sock_fd < 0) {
- osrfLogWarning( OSRF_LOG_MARK, "tcp_server_connect(): Unable to create socket");
+ osrfLogWarning( OSRF_LOG_MARK, "socket_open_tcp_server(): Unable to create TCP socket: %s",
+ strerror( errno ) );
return -1;
}
server_addr.sin_port = htons(port);
+ errno = 0;
if(bind( sock_fd, (struct sockaddr*) &server_addr, sizeof(server_addr)) < 0) {
- osrfLogWarning( OSRF_LOG_MARK, "tcp_server_connect(): cannot bind to port %d", port );
+ osrfLogWarning( OSRF_LOG_MARK, "socket_open_tcp_server(): cannot bind to port %d: %s",
+ port, strerror( errno ) );
return -1;
}
+ errno = 0;
if(listen(sock_fd, 20) == -1) {
- osrfLogWarning( OSRF_LOG_MARK, "tcp_server_connect(): listen() returned error");
+ osrfLogWarning( OSRF_LOG_MARK, "socket_open_tcp_server(): listen() returned error: %s",
+ strerror( errno ) );
return -1;
}
int sock_fd;
struct sockaddr_un server_addr;
+ errno = 0;
sock_fd = socket(AF_UNIX, SOCK_STREAM, 0);
if(sock_fd < 0){
- osrfLogWarning( OSRF_LOG_MARK, "socket_open_unix_server(): socket() failed");
+ osrfLogWarning( OSRF_LOG_MARK, "socket_open_unix_server(): socket() failed: %s",
+ strerror( errno ) );
return -1;
}
server_addr.sun_family = AF_UNIX;
strcpy(server_addr.sun_path, path);
+ errno = 0;
if( bind(sock_fd, (struct sockaddr*) &server_addr,
sizeof(struct sockaddr_un)) < 0) {
osrfLogWarning( OSRF_LOG_MARK,
- "socket_open_unix_server(): cannot bind to unix port %s", path );
+ "socket_open_unix_server(): cannot bind to unix port %s: %s",
+ path, strerror( errno ) );
return -1;
}
+ errno = 0;
if(listen(sock_fd, 20) == -1) {
- osrfLogWarning( OSRF_LOG_MARK, "socket_open_unix_server(): listen() returned error");
+ osrfLogWarning( OSRF_LOG_MARK, "socket_open_unix_server(): listen() returned error: %s",
+ strerror( errno ) );
return -1;
}
int sockfd;
struct sockaddr_in server_addr;
+ errno = 0;
if( (sockfd = socket( AF_INET, SOCK_DGRAM, 0 )) < 0 ) {
- osrfLogWarning( OSRF_LOG_MARK, "Unable to create UDP socket");
+ osrfLogWarning( OSRF_LOG_MARK, "Unable to create UDP socket: %s", strerror( errno ) );
return -1;
}
if(listen_ip) server_addr.sin_addr.s_addr = inet_addr(listen_ip);
else server_addr.sin_addr.s_addr = htonl(INADDR_ANY);
+ errno = 0;
if( (bind (sockfd, (struct sockaddr *) &server_addr,sizeof(server_addr))) ) {
- osrfLogWarning( OSRF_LOG_MARK, "Unable to bind to UDP port %d", port);
+ osrfLogWarning( OSRF_LOG_MARK, "Unable to bind to UDP port %d: %s",
+ port, strerror( errno ) );
return -1;
}
// ------------------------------------------------------------------
// Create the socket
// ------------------------------------------------------------------
+ errno = 0;
if( (sock_fd = socket( AF_INET, SOCK_STREAM, 0 )) < 0 ) {
- osrfLogWarning( OSRF_LOG_MARK, "tcp_connect(): Cannot create socket" );
+ osrfLogWarning( OSRF_LOG_MARK, "socket_open_tcp_client(): Cannot create TCP socket: %s",
+ strerror( errno ) );
return -1;
}
// ------------------------------------------------------------------
// Get the hostname
// ------------------------------------------------------------------
+ errno = 0;
if( (hptr = gethostbyname( dest_addr ) ) == NULL ) {
- osrfLogWarning( OSRF_LOG_MARK, "tcp_connect(): Unknown Host => %s", dest_addr );
+ osrfLogWarning( OSRF_LOG_MARK, "socket_open_tcp_client(): Unknown Host => %s: %s",
+ dest_addr, strerror( errno ) );
return -1;
}
// ------------------------------------------------------------------
// Bind to a local port
// ------------------------------------------------------------------
+ errno = 0;
if( bind( sock_fd, (struct sockaddr *) &localAddr, sizeof( localAddr ) ) < 0 ) {
- osrfLogWarning( OSRF_LOG_MARK, "tcp_connect(): Cannot bind to local port" );
+ osrfLogWarning( OSRF_LOG_MARK, "socket_open_tcp_client(): Cannot bind to local port: %s",
+ strerror( errno ) );
return -1;
}
// ------------------------------------------------------------------
// Connect to server
// ------------------------------------------------------------------
+ errno = 0;
if( connect( sock_fd, (struct sockaddr*) &remoteAddr, sizeof( struct sockaddr_in ) ) < 0 ) {
- osrfLogWarning( OSRF_LOG_MARK, "tcp_connect(): Cannot connect to server %s", dest_addr );
- return -1;
+ osrfLogWarning( OSRF_LOG_MARK, "socket_open_tcp_client(): Cannot connect to server %s: %s",
+ dest_addr, strerror(errno) );
+ return -1;
}
_socket_add_node(mgr, CLIENT_SOCKET, INET, sock_fd, -1 );
struct sockaddr_in client_addr, server_addr;
struct hostent* host;
+ errno = 0;
if( (host = gethostbyname(dest_addr)) == NULL) {
- osrfLogWarning( OSRF_LOG_MARK, "Unable to resolve host: %s", dest_addr);
+ osrfLogWarning( OSRF_LOG_MARK, "Unable to resolve host: %s: %s",
+ dest_addr, strerror( errno ) );
return -1;
}
host->h_addr_list[0], host->h_length);
server_addr.sin_port = htons(port);
+ errno = 0;
if( (sockfd = socket(AF_INET,SOCK_DGRAM,0)) < 0 ) {
- osrfLogWarning( OSRF_LOG_MARK, "Unable to create UDP socket");
+ osrfLogWarning( OSRF_LOG_MARK, "socket_open_udp_client(): Unable to create UDP socket: %s", strerror( errno ) );
return -1;
}
client_addr.sin_addr.s_addr = htonl(INADDR_ANY);
client_addr.sin_port = htons(0);
+ errno = 0;
if( (bind(sockfd, (struct sockaddr *) &client_addr, sizeof(client_addr))) < 0 ) {
- osrfLogWarning( OSRF_LOG_MARK, "Unable to bind UDP socket");
+ osrfLogWarning( OSRF_LOG_MARK, "Unable to bind UDP socket: %s", strerror( errno ) );
return -1;
}
int sock_fd, len;
struct sockaddr_un usock;
+ errno = 0;
if( (sock_fd = socket( AF_UNIX, SOCK_STREAM, 0 )) < 0 ) {
- osrfLogWarning( OSRF_LOG_MARK, "Cannot create socket" );
+ osrfLogWarning( OSRF_LOG_MARK, "socket_open_unix_client(): Cannot create UNIX socket: %s", strerror( errno ) );
return -1;
}
len = sizeof( usock.sun_family ) + strlen( usock.sun_path );
+ errno = 0;
if( connect( sock_fd, (struct sockaddr *) &usock, len ) < 0 ) {
- osrfLogWarning( OSRF_LOG_MARK, "Error connecting to unix socket" );
+ osrfLogWarning( OSRF_LOG_MARK, "Error connecting to unix socket: %s",
+ strerror( errno ) );
return -1;
}
}
-
/* returns the socket_node with the given sock_fd */
-socket_node* socket_find_node(socket_manager* mgr, int sock_fd) {
+static socket_node* socket_find_node(socket_manager* mgr, int sock_fd) {
if(mgr == NULL) return NULL;
socket_node* node = mgr->socket;
while(node) {
}
/* removes the node with the given sock_fd from the list and frees it */
-void socket_remove_node(socket_manager* mgr, int sock_fd) {
+static void socket_remove_node(socket_manager* mgr, int sock_fd) {
if(mgr == NULL) return;
}
-
void _socket_print_list(socket_manager* mgr) {
if(mgr == NULL) return;
socket_node* node = mgr->socket;
return _socket_send( sock_fd, data, 0);
}
-
-int _socket_send(int sock_fd, const char* data, int flags) {
+/* utility method */
+static int _socket_send(int sock_fd, const char* data, int flags) {
signal(SIGPIPE, SIG_IGN); /* in case a unix socket was closed */
+ errno = 0;
size_t r = send( sock_fd, data, strlen(data), flags );
-
+ int local_errno = errno;
+
if( r == -1 ) {
- osrfLogWarning( OSRF_LOG_MARK, "tcp_server_send(): Error sending data with return %d", r );
- osrfLogWarning( OSRF_LOG_MARK, "Last Sys Error: %s", strerror(errno));
+ osrfLogWarning( OSRF_LOG_MARK, "_socket_send(): Error sending data with return %d", r );
+ osrfLogWarning( OSRF_LOG_MARK, "Last Sys Error: %s", strerror(local_errno));
return -1;
}
}
-int socket_send_nowait( int sock_fd, const char* data) {
- return _socket_send( sock_fd, data, MSG_DONTWAIT);
-}
+/* sends the given data to the given socket.
+ * sets the send flag MSG_DONTWAIT which will allow the
+ * process to continue even if the socket buffer is full
+ * returns 0 on success, -1 otherwise */
+//int socket_send_nowait( int sock_fd, const char* data) {
+// return _socket_send( sock_fd, data, MSG_DONTWAIT);
+//}
/*
tv.tv_sec = secs;
tv.tv_usec = usecs;
+ errno = 0;
int ret = select( sock_fd + 1, NULL, &write_set, NULL, &tv);
if( ret > 0 ) return _socket_send( sock_fd, data, 0);
osrfLogError(OSRF_LOG_MARK, "socket_send_timeout(): "
- "timed out on send for socket %d after %d secs, %d usecs", sock_fd, secs, usecs );
+ "timed out on send for socket %d after %d secs, %d usecs: %s",
+ sock_fd, secs, usecs, strerror( errno ) );
return -1;
}
struct timeval tv;
tv.tv_sec = timeout;
tv.tv_usec = 0;
+ errno = 0;
if( timeout < 0 ) {
int socket_wait_all(socket_manager* mgr, int timeout) {
if(mgr == NULL) {
- osrfLogWarning( OSRF_LOG_MARK, "tcp_wait(): null mgr" );
+ osrfLogWarning( OSRF_LOG_MARK, "socket_wait_all(): null mgr" );
return -1;
}
struct timeval tv;
tv.tv_sec = timeout;
tv.tv_usec = 0;
+ errno = 0;
if( timeout < 0 ) {
// If timeout is -1, there is no timeout passed to the call to select
if( (retval = select( max_fd, &read_set, NULL, NULL, NULL)) == -1 ) {
- osrfLogWarning( OSRF_LOG_MARK, "Call to select interrupted (returned -1)");
- osrfLogWarning( OSRF_LOG_MARK, "Sys Error: %s", strerror(errno));
+ osrfLogWarning( OSRF_LOG_MARK, "select() call aborted: %s", strerror(errno));
return -1;
}
} else if( timeout != 0 ) { /* timeout of 0 means don't block */
if( (retval = select( max_fd, &read_set, NULL, NULL, &tv)) == -1 ) {
- osrfLogWarning( OSRF_LOG_MARK, "Call to select interrupted (returned -1)" );
- osrfLogWarning( OSRF_LOG_MARK, "Sys Error: %s", strerror(errno));
+ osrfLogWarning( OSRF_LOG_MARK, "select() call aborted: %s", strerror(errno));
return -1;
}
}
return _socket_route_data(mgr, retval, &read_set);
}
-/* determines if we'er receiving a new client or data
+/* iterates over the sockets in the set and handles active sockets.
+ new sockets connecting to server sockets cause the creation
+ of a new socket node.
+ Any new data read is is passed off to the data_received callback
+ as it arrives */
+/* determines if we're receiving a new client or data
on an existing client */
-int _socket_route_data(
+static int _socket_route_data(
socket_manager* mgr, int num_active, fd_set* read_set) {
if(!(mgr && read_set)) return -1;
}
-int _socket_route_data_id( socket_manager* mgr, int sock_id) {
+/* routes data from a single known socket */
+static int _socket_route_data_id( socket_manager* mgr, int sock_id) {
socket_node* node = socket_find_node(mgr, sock_id);
int status = 0;
}
-int _socket_handle_new_client(socket_manager* mgr, socket_node* node) {
+static int _socket_handle_new_client(socket_manager* mgr, socket_node* node) {
if(mgr == NULL || node == NULL) return -1;
+ errno = 0;
int new_sock_fd;
new_sock_fd = accept(node->sock_fd, NULL, NULL);
if(new_sock_fd < 0) {
- osrfLogWarning( OSRF_LOG_MARK, "_socket_route_data(): accept() failed");
+ osrfLogWarning( OSRF_LOG_MARK, "_socket_handle_new_client(): accept() failed: %s",
+ strerror( errno ) );
return -1;
}
}
-int _socket_handle_client_data(socket_manager* mgr, socket_node* node) {
+static int _socket_handle_client_data(socket_manager* mgr, socket_node* node) {
if(mgr == NULL || node == NULL) return -1;
char buf[RBUFSIZE];
memset(buf, 0, RBUFSIZE);
set_fl(sock_fd, O_NONBLOCK);
- osrfLogInternal( OSRF_LOG_MARK, "%d : Received data at %f\n", getpid(), get_timestamp_millis());
+ osrfLogInternal( OSRF_LOG_MARK, "%ld : Received data at %f\n", (long) getpid(), get_timestamp_millis());
while( (read_bytes = recv(sock_fd, buf, RBUFSIZE-1, 0) ) > 0 ) {
osrfLogInternal( OSRF_LOG_MARK, "Socket %d Read %d bytes and data: %s", sock_fd, read_bytes, buf);
memset(buf, 0, RBUFSIZE);
}
+ int local_errno = errno; /* capture errno as set by recv() */
if(socket_find_node(mgr, sock_fd)) { /* someone may have closed this socket */
clr_fl(sock_fd, O_NONBLOCK);
if(read_bytes < 0) {
- if( errno != EAGAIN )
- osrfLogWarning( OSRF_LOG_MARK, " * Error reading socket with errno %d", errno );
+ if(local_errno != EAGAIN)
+ osrfLogWarning(OSRF_LOG_MARK, " * Error reading socket with error %s", strerror(local_errno));
}
} else { return -1; } /* inform the caller that this node has been tampered with */
free(mgr);
}
+
#define INET 10
#define UNIX 11
-/* buffer used to read from the sockets */
-#define RBUFSIZE 1024
-
/* models a single socket connection */
struct socket_node_struct {
int socket_open_udp_client( socket_manager* mgr, int port, char* dest_addr);
-/* returns the socket_node with the given sock_fd */
-socket_node* socket_find_node(socket_manager*, int sock_fd);
-
-/* removes the node with the given sock_fd from the list and frees it */
-void socket_remove_node(socket_manager*, int sock_fd);
-
-
/* sends the given data to the given socket. returns 0 on success, -1 otherwise */
int socket_send(int sock_fd, const char* data);
-/* utility method */
-int _socket_send(int sock_fd, const char* data, int flags);
-
-
-/* sends the given data to the given socket.
- * sets the send flag MSG_DONTWAIT which will allow the
- * process to continue even if the socket buffer is full
- * returns 0 on success, -1 otherwise */
-int socket_send_nowait( int sock_fd, const char* data);
-
/* waits at most usecs microseconds for the socket buffer to
* be available */
int socket_send_timeout( int sock_fd, const char* data, int usecs );
it from the socket set */
void socket_disconnect(socket_manager*, int sock_fd);
-/* allocates and inserts a new socket node into the nodeset.
- if parent_id is positive and non-zero, it will be set */
-socket_node* _socket_add_node(socket_manager* mgr,
- int endpoint, int addr_type, int sock_fd, int parent_id );
-
/* XXX This only works if 'sock_fd' is a client socket... */
int socket_wait(socket_manager* mgr, int timeout, int sock_fd);
timeout == x | block for at most x seconds */
int socket_wait_all(socket_manager* mgr, int timeout);
-/* iterates over the sockets in the set and handles active sockets.
- new sockets connecting to server sockets cause the creation
- of a new socket node.
- Any new data read is is passed off to the data_received callback
- as it arrives */
-int _socket_route_data(socket_manager* mgr, int num_active, fd_set* read_set);
-
-/* routes data from a single known socket */
-int _socket_route_data_id( socket_manager* mgr, int sock_id);
-
/* utility function for displaying the currently attached sockets */
void _socket_print_list(socket_manager* mgr);
int socket_connected(int sock_fd);
-
-int _socket_handle_new_client(socket_manager* mgr, socket_node* node);
-int _socket_handle_client_data(socket_manager* mgr, socket_node* node);
-
-
#endif
return ptr;
}
-
-char** __global_argv = NULL;
-int __global_argv_size = 0;
+/****************
+ The following static variables, and the following two functions,
+ overwrite the argv array passed to main(). The purpose is to
+ change the program name as reported by ps and similar utilities.
+
+ Warning: this code makes the non-portable assumption that the
+ strings to which argv[] points are contiguous in memory. The
+ C Standard makes no such guarantee.
+ ****************/
+static char** global_argv = NULL;
+static int global_argv_size = 0;
int init_proc_title( int argc, char* argv[] ) {
- __global_argv = argv;
+ global_argv = argv;
int i = 0;
while( i < argc ) {
- int len = strlen( __global_argv[i]);
- bzero( __global_argv[i++], len );
- __global_argv_size += len;
+ int len = strlen( global_argv[i]);
+ bzero( global_argv[i++], len );
+ global_argv_size += len;
}
- __global_argv_size -= 2;
+ global_argv_size -= 2;
return 0;
}
int set_proc_title( char* format, ... ) {
VA_LIST_TO_STRING(format);
- bzero( *(__global_argv), __global_argv_size );
- return snprintf( *(__global_argv), __global_argv_size, VA_BUF );
+ bzero( *(global_argv), global_argv_size );
+ return snprintf( *(global_argv), global_argv_size, VA_BUF );
}
int val;
- if( (val = fcntl( fd, F_GETFL, 0) ) < 0 ) {
- fprintf(stderr, "fcntl F_GETFL error");
+ if( (val = fcntl( fd, F_GETFL, 0) ) < 0 )
return -1;
- }
val |= flags;
- if( fcntl( fd, F_SETFL, val ) < 0 ) {
- fprintf(stderr, "fcntl F_SETFL error");
+ if( fcntl( fd, F_SETFL, val ) < 0 )
return -1;
- }
+
return 0;
}
int val;
- if( (val = fcntl( fd, F_GETFL, 0) ) < 0 ) {
- fprintf(stderr, "fcntl F_GETFL error" );
+ if( (val = fcntl( fd, F_GETFL, 0) ) < 0 )
return -1;
- }
val &= ~flags;
- if( fcntl( fd, F_SETFL, val ) < 0 ) {
- fprintf( stderr, "fcntl F_SETFL error" );
+ if( fcntl( fd, F_SETFL, val ) < 0 )
return -1;
- }
+
return 0;
}
return 1;
}
+/* Return a pointer to the text within a growing_buffer, */
+/* while destroying the growing_buffer itself. */
+
+char* buffer_release( growing_buffer* gb) {
+ char* s = gb->buf;
+ s[gb->n_used] = '\0';
+ free( gb );
+ return s;
+}
+
+/* Destroy a growing_buffer and the text it contains */
+
int buffer_free( growing_buffer* gb ) {
if( gb == NULL )
return 0;
#define OSRF_MALLOC(ptr, size) \
- ptr = (void*) malloc( size ); \
- if( ptr == NULL ) { \
- perror("OSRF_MALLOC(): Out of Memory" );\
- exit(99); \
- } \
- memset( ptr, 0, size );
+ do {\
+ ptr = (void*) malloc( size ); \
+ if( ptr == NULL ) { \
+ perror("OSRF_MALLOC(): Out of Memory" );\
+ exit(99); \
+ } \
+ memset( ptr, 0, size );\
+ } while(0)
#define OSRF_BUFFER_ADD(gb, data) \
int buffer_fadd(growing_buffer* gb, const char* format, ... );
int buffer_reset( growing_buffer* gb);
char* buffer_data( growing_buffer* gb);
+char* buffer_release( growing_buffer* gb );
int buffer_free( growing_buffer* gb );
int buffer_add_char(growing_buffer* gb, char c);
}
xmlNodePtr child = node->children;
- while(child) {
- _xmlToJSON(child, new_obj);
- child = child->next;
- }
+ if (child) { // at least one...
+ if (child != node->last) { // more than one -- ignore TEXT nodes
+ while(child) {
+ if (child->type != XML_TEXT_NODE) _xmlToJSON(child, new_obj);
+ child = child->next;
+ }
+ } else {
+ _xmlToJSON(child, new_obj);
+ }
+ }
}
return obj;