From: erickson Date: Wed, 13 Jun 2007 14:03:35 +0000 (+0000) Subject: Merging trunk into new-json branch to keep the branch in sync with trunk X-Git-Url: https://old-git.evergreen-ils.org/?a=commitdiff_plain;h=refs%2Fheads%2Fnew-json;p=OpenSRF.git Merging trunk into new-json branch to keep the branch in sync with trunk $ svn merge -r 887:HEAD svn://svn.open-ils.org/OpenSRF/trunk revision 887 is the changeset for the creation of the new-json branch this is the first sync merge git-svn-id: svn://svn.open-ils.org/OpenSRF/branches/new-json@946 9efc2488-bf62-4759-914b-345cdb29e865 --- diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..a23c57c --- /dev/null +++ b/Makefile @@ -0,0 +1,14 @@ +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 diff --git a/examples/srfsh_config.xsd b/examples/srfsh_config.xsd new file mode 100644 index 0000000..9f1fd8d --- /dev/null +++ b/examples/srfsh_config.xsd @@ -0,0 +1,77 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/install.conf b/install.conf new file mode 100644 index 0000000..35911d6 --- /dev/null +++ b/install.conf @@ -0,0 +1,14 @@ +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/ diff --git a/src/Makefile b/src/Makefile index 0ad9171..8b33c95 100644 --- a/src/Makefile +++ b/src/Makefile @@ -9,7 +9,7 @@ export PERLDIR = $(LIBDIR)/perl5 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) @@ -135,7 +135,6 @@ install-prep: mkdir -p $(INCLUDEDIR) mkdir -p $(INCLUDEDIR)/$(OPENSRF) mkdir -p $(ETCDIR) - mkdir -p $(TEMPLATEDIR) libopensrf-install: install-prep @echo $@ diff --git a/src/java/Makefile b/src/java/Makefile index 67891e7..7bcd020 100644 --- a/src/java/Makefile +++ b/src/java/Makefile @@ -2,7 +2,7 @@ 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 \ @@ -25,7 +25,15 @@ check: @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; diff --git a/src/java/ext/stax-api-1.0.1.jar b/src/java/ext/stax-api-1.0.1.jar deleted file mode 100644 index 162b3fb..0000000 Binary files a/src/java/ext/stax-api-1.0.1.jar and /dev/null differ diff --git a/src/java/ext/wstx-asl-3.2.1.jar b/src/java/ext/wstx-asl-3.2.1.jar deleted file mode 100644 index 581f825..0000000 Binary files a/src/java/ext/wstx-asl-3.2.1.jar and /dev/null differ diff --git a/src/java/org/opensrf/ClientSession.java b/src/java/org/opensrf/ClientSession.java index 09cfce1..cc68505 100644 --- a/src/java/org/opensrf/ClientSession.java +++ b/src/java/org/opensrf/ClientSession.java @@ -8,6 +8,7 @@ import java.util.Random; import java.util.Arrays; import org.opensrf.util.*; +import org.opensrf.net.xmpp.*; /** @@ -41,8 +42,8 @@ public class ClientSession extends Session { 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(); @@ -111,7 +112,7 @@ public class ClientSession extends Session { */ 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; @@ -128,11 +129,21 @@ public class ClientSession extends Session { ); } + 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(); + } } diff --git a/src/java/org/opensrf/Request.java b/src/java/org/opensrf/Request.java index 001ce43..e5d0ef6 100644 --- a/src/java/org/opensrf/Request.java +++ b/src/java/org/opensrf/Request.java @@ -69,11 +69,11 @@ public class Request { * 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) @@ -81,7 +81,7 @@ public class Request { } 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 @@ -120,4 +120,9 @@ public class Request { public void cleanup() { session.cleanupRequest(id); } + + /** Sets this request as complete */ + public void setComplete() { + complete = true; + } } diff --git a/src/java/org/opensrf/Session.java b/src/java/org/opensrf/Session.java index 3dc81f9..e2b41c3 100644 --- a/src/java/org/opensrf/Session.java +++ b/src/java/org/opensrf/Session.java @@ -60,7 +60,7 @@ public abstract class Session { * 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)); diff --git a/src/java/org/opensrf/SessionException.java b/src/java/org/opensrf/SessionException.java new file mode 100644 index 0000000..bd90a76 --- /dev/null +++ b/src/java/org/opensrf/SessionException.java @@ -0,0 +1,13 @@ +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); + } +} + diff --git a/src/java/org/opensrf/Stack.java b/src/java/org/opensrf/Stack.java index 6db285e..36dba52 100644 --- a/src/java/org/opensrf/Stack.java +++ b/src/java/org/opensrf/Stack.java @@ -8,10 +8,12 @@ import java.util.Iterator; 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()); @@ -55,7 +57,7 @@ public class Stack { /** 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 @@ -65,11 +67,30 @@ public class Stack { /** * 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); + } + } } /** diff --git a/src/java/org/opensrf/Status.java b/src/java/org/opensrf/Status.java new file mode 100644 index 0000000..8026c7b --- /dev/null +++ b/src/java/org/opensrf/Status.java @@ -0,0 +1,63 @@ +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; + } +} + + diff --git a/src/java/org/opensrf/Sys.java b/src/java/org/opensrf/Sys.java new file mode 100644 index 0000000..8520838 --- /dev/null +++ b/src/java/org/opensrf/Sys.java @@ -0,0 +1,47 @@ +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(); + } +} + diff --git a/src/java/org/opensrf/net/xmpp/XMPPSession.java b/src/java/org/opensrf/net/xmpp/XMPPSession.java index ce7e36c..e8b639e 100644 --- a/src/java/org/opensrf/net/xmpp/XMPPSession.java +++ b/src/java/org/opensrf/net/xmpp/XMPPSession.java @@ -19,6 +19,8 @@ public class XMPPSession { "" + "%s%s%s"; + public static final String JABBER_DISCONNECT = ""; + /** jabber domain */ private String host; /** jabber port */ @@ -36,6 +38,8 @@ public class XMPPSession { PrintWriter writer; /** Raw socket output stream */ OutputStream outStream; + /** The raw socket */ + Socket socket; /** The process-wide session. All communication occurs * accross this single connection */ @@ -88,8 +92,6 @@ public class XMPPSession { this.password = password; this.resource = resource; - Socket socket; - try { /* open the socket and associated streams */ socket = new Socket(host, port); @@ -193,5 +195,16 @@ public class XMPPSession { 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) {} + } } diff --git a/src/java/org/opensrf/test/MathBench.java b/src/java/org/opensrf/test/MathBench.java new file mode 100644 index 0000000..b6e67f9 --- /dev/null +++ b/src/java/org/opensrf/test/MathBench.java @@ -0,0 +1,79 @@ +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 "); + 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 params = new ArrayList(); + 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(); + } +} + + + diff --git a/src/java/org/opensrf/test/TestCache.java b/src/java/org/opensrf/test/TestCache.java new file mode 100644 index 0000000..1e47c32 --- /dev/null +++ b/src/java/org/opensrf/test/TestCache.java @@ -0,0 +1,27 @@ +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")); + } +} + + diff --git a/src/java/org/opensrf/test/TestClient.java b/src/java/org/opensrf/test/TestClient.java index 8cd7865..2625053 100644 --- a/src/java/org/opensrf/test/TestClient.java +++ b/src/java/org/opensrf/test/TestClient.java @@ -1,61 +1,54 @@ 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 "+ + " [, ]"); + 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 params = new ArrayList(); + 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 "); - 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."); } } diff --git a/src/java/org/opensrf/test/TestConfig.java b/src/java/org/opensrf/test/TestConfig.java index 5cd4eb3..f65a84f 100644 --- a/src/java/org/opensrf/test/TestConfig.java +++ b/src/java/org/opensrf/test/TestConfig.java @@ -11,6 +11,6 @@ public class TestConfig { 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])); } } diff --git a/src/java/org/opensrf/test/TestSettings.java b/src/java/org/opensrf/test/TestSettings.java new file mode 100644 index 0000000..116bbe1 --- /dev/null +++ b/src/java/org/opensrf/test/TestSettings.java @@ -0,0 +1,14 @@ +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); + } +} diff --git a/src/java/org/opensrf/util/Cache.java b/src/java/org/opensrf/util/Cache.java new file mode 100644 index 0000000..5303688 --- /dev/null +++ b/src/java/org/opensrf/util/Cache.java @@ -0,0 +1,38 @@ +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 serverList) { + initCache(serverList.toArray(new String[]{})); + } +} + diff --git a/src/java/org/opensrf/util/Config.java b/src/java/org/opensrf/util/Config.java index 7b3a0bf..ddac9c0 100644 --- a/src/java/org/opensrf/util/Config.java +++ b/src/java/org/opensrf/util/Config.java @@ -23,6 +23,11 @@ public class Config { */ private String context; + public static Config global() { + return config; + } + + /** * @param context The config context */ @@ -34,7 +39,7 @@ public class Config { * 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; } @@ -42,19 +47,36 @@ public class Config { * 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) { @@ -67,7 +89,7 @@ public class Config { * 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) { @@ -82,9 +104,9 @@ public class Config { * @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; @@ -99,7 +121,7 @@ public class Config { * 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); diff --git a/src/java/org/opensrf/util/ConfigException.java b/src/java/org/opensrf/util/ConfigException.java index be7c0cf..c1c491e 100644 --- a/src/java/org/opensrf/util/ConfigException.java +++ b/src/java/org/opensrf/util/ConfigException.java @@ -8,4 +8,7 @@ public class ConfigException extends Exception { public ConfigException(String info) { super(info); } + public ConfigException(String info, Throwable t) { + super(info, t); + } } diff --git a/src/java/org/opensrf/util/SettingsClient.java b/src/java/org/opensrf/util/SettingsClient.java new file mode 100644 index 0000000..cd70ebb --- /dev/null +++ b/src/java/org/opensrf/util/SettingsClient.java @@ -0,0 +1,53 @@ +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(); + } + } +} + diff --git a/src/jserver/osrf_chat.c b/src/jserver/osrf_chat.c index 55b3c33..2585719 100644 --- a/src/jserver/osrf_chat.c +++ b/src/jserver/osrf_chat.c @@ -18,8 +18,8 @@ GNU General Public License for more details. #include #include -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)); } @@ -83,14 +83,16 @@ osrfChatServer* osrfNewChatServer( char* domain, char* secret, int s2sport ) { 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; } @@ -192,8 +194,12 @@ void osrfChatServerFree(osrfChatServer* server ) { if(!server) return; osrfHashFree(server->nodeHash); osrfListFree(server->nodeList); + osrfListFree(server->deadNodes); free(server->mgr); + free(server->domain); free(server->secret); + + free(server); } @@ -399,16 +405,16 @@ int osrfChatPushData( osrfChatServer* server, osrfChatNode* node, char* data ) { 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 ); } */ @@ -587,7 +593,7 @@ int osrfChatHandleNewConnection( osrfChatNode* node, const char* name, const xml 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)); } @@ -797,7 +803,7 @@ void osrfChatHandleCharacter( void* blob, const xmlChar *ch, int len) { void osrfChatParseError( void* blob, const char* msg, ... ) { - __osrfChatXMLErrorOcurred = 1; + osrfChatXMLErrorOcurred = 1; } diff --git a/src/jserver/osrf_chat_main.c b/src/jserver/osrf_chat_main.c index 401d3b4..8ac5298 100644 --- a/src/jserver/osrf_chat_main.c +++ b/src/jserver/osrf_chat_main.c @@ -13,6 +13,10 @@ int main( int argc, char* argv[] ) { } 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" ); @@ -26,6 +30,27 @@ int main( int argc, char* argv[] ) { 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; @@ -35,10 +60,8 @@ int main( int argc, char* argv[] ) { 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 { diff --git a/src/libstack/opensrf.c b/src/libstack/opensrf.c index 2277eb4..9291930 100644 --- a/src/libstack/opensrf.c +++ b/src/libstack/opensrf.c @@ -21,13 +21,22 @@ int main( int argc, char* argv[] ) { 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; } diff --git a/src/libstack/osrfConfig.c b/src/libstack/osrfConfig.c index c195a19..81e6623 100644 --- a/src/libstack/osrfConfig.c +++ b/src/libstack/osrfConfig.c @@ -1,11 +1,15 @@ /* 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) { @@ -18,13 +22,13 @@ void osrfConfigFree(osrfConfig* cfg) { int osrfConfigHasDefaultConfig() { - return ( __osrfConfigDefault != NULL ); + return ( osrfConfigDefault != NULL ); } void osrfConfigCleanup() { - osrfConfigFree(__osrfConfigDefault); - __osrfConfigDefault = NULL; + osrfConfigFree(osrfConfigDefault); + osrfConfigDefault = NULL; } @@ -37,19 +41,17 @@ void osrfConfigReplaceConfig(osrfConfig* cfg, const jsonObject* obj) { 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); @@ -59,19 +61,28 @@ osrfConfig* osrfConfigInit(char* configFile, char* configContext) { 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); @@ -95,7 +106,7 @@ char* osrfConfigGetValue(osrfConfig* cfg, char* 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); diff --git a/src/libstack/osrf_app_session.c b/src/libstack/osrf_app_session.c index 770446f..095e50e 100644 --- a/src/libstack/osrf_app_session.c +++ b/src/libstack/osrf_app_session.c @@ -229,7 +229,7 @@ osrf_app_session* osrf_app_client_session_init( char* remote_service ) { 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 ); @@ -598,6 +598,7 @@ int osrfAppRequestRespond( osrfAppSession* ses, int requestId, jsonObject* data 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 ); diff --git a/src/libstack/osrf_prefork.c b/src/libstack/osrf_prefork.c index 31548e9..1ea5959 100644 --- a/src/libstack/osrf_prefork.c +++ b/src/libstack/osrf_prefork.c @@ -586,7 +586,7 @@ void prefork_child_wait( prefork_child* child ) { 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; } @@ -606,8 +606,8 @@ void prefork_child_wait( prefork_child* child ) { 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 */ } diff --git a/src/libstack/osrf_settings.c b/src/libstack/osrf_settings.c index fa8d98e..26e3b8f 100644 --- a/src/libstack/osrf_settings.c +++ b/src/libstack/osrf_settings.c @@ -4,6 +4,14 @@ osrf_host_config* config = NULL; 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); @@ -36,7 +44,17 @@ int osrf_settings_retrieve(char* hostname) { 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); diff --git a/src/libstack/osrf_system.c b/src/libstack/osrf_system.c index 68f2e3c..dc6b2ba 100644 --- a/src/libstack/osrf_system.c +++ b/src/libstack/osrf_system.c @@ -3,20 +3,20 @@ #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 ) { @@ -28,7 +28,7 @@ int osrfSystemBootstrapClientResc( char* config_file, char* contextnode, char* r } -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"); @@ -64,13 +64,22 @@ int osrfSystemBootstrap( char* hostname, char* configfile, char* contextNode ) { /* 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); @@ -105,11 +114,11 @@ int osrfSystemBootstrap( char* hostname, char* configfile, char* contextNode ) { 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 { @@ -117,7 +126,7 @@ int osrfSystemBootstrap( char* hostname, char* configfile, char* contextNode ) { 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 @@ -128,16 +137,28 @@ int osrfSystemBootstrap( char* hostname, char* configfile, char* contextNode ) { /* 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 */ @@ -149,39 +170,50 @@ int osrf_system_bootstrap_client_resc( char* config_file, char* contextnode, cha } 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)); @@ -192,15 +224,55 @@ int osrf_system_bootstrap_client_resc( char* config_file, char* contextnode, cha 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 = ""; @@ -208,15 +280,16 @@ int osrf_system_bootstrap_client_resc( char* config_file, char* contextnode, cha 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); @@ -225,22 +298,21 @@ int osrf_system_bootstrap_client_resc( char* config_file, char* contextnode, cha 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); @@ -252,16 +324,3 @@ int osrf_system_shutdown() { -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 **/ -} - - diff --git a/src/libstack/osrf_system.h b/src/libstack/osrf_system.h index bc2e456..3a87008 100644 --- a/src/libstack/osrf_system.h +++ b/src/libstack/osrf_system.h @@ -38,14 +38,12 @@ int osrf_system_bootstrap_client_resc( char* config_file, char* contextnode, cha */ 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 diff --git a/src/libtransport/basic_client.c b/src/libtransport/basic_client.c index d2178eb..d7fa9a1 100644 --- a/src/libtransport/basic_client.c +++ b/src/libtransport/basic_client.c @@ -29,7 +29,7 @@ int main( int argc, char** argv ) { 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("=> "); @@ -56,7 +56,7 @@ int main( int argc, char** argv ) { } else { - fprintf(stderr, "Sender: %d\n", getpid() ); + fprintf(stderr, "Sender: %ld\n", (long) getpid() ); transport_message* recv; while( (recv=client_recv( client, -1)) ) { diff --git a/src/libtransport/transport_client.c b/src/libtransport/transport_client.c index 32e3920..a318127 100644 --- a/src/libtransport/transport_client.c +++ b/src/libtransport/transport_client.c @@ -45,19 +45,24 @@ int main( int argc, char** argv ) { */ -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; diff --git a/src/libtransport/transport_client.h b/src/libtransport/transport_client.h index aa0b921..50a2c66 100644 --- a/src/libtransport/transport_client.h +++ b/src/libtransport/transport_client.h @@ -42,7 +42,7 @@ typedef struct transport_client_struct transport_client; // 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 ); // --------------------------------------------------------------------------- diff --git a/src/libtransport/transport_session.c b/src/libtransport/transport_session.c index 1db881a..42958b3 100644 --- a/src/libtransport/transport_session.c +++ b/src/libtransport/transport_session.c @@ -6,8 +6,8 @@ // 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 = @@ -119,7 +119,7 @@ int session_wait( transport_session* session, int timeout ) { 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; @@ -171,6 +171,10 @@ int session_connect( transport_session* session, 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 ) { diff --git a/src/libtransport/transport_session.h b/src/libtransport/transport_session.h index ba02e5b..78d108b 100644 --- a/src/libtransport/transport_session.h +++ b/src/libtransport/transport_session.h @@ -186,8 +186,8 @@ typedef struct transport_session_struct transport_session; // 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 diff --git a/src/objson/json2xml.h b/src/objson/json2xml.h index 47b5a4f..5998150 100644 --- a/src/objson/json2xml.h +++ b/src/objson/json2xml.h @@ -5,7 +5,7 @@ /* 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*); diff --git a/src/objson/json_parser.h b/src/objson/json_parser.h index 32b6298..f6d9803 100644 --- a/src/objson/json_parser.h +++ b/src/objson/json_parser.h @@ -24,7 +24,7 @@ GNU General Public License for more details. #include #include "object.h" -#include "utils.h" +#include "opensrf/utils.h" diff --git a/src/objson/object.h b/src/objson/object.h index baa63e9..d782574 100644 --- a/src/objson/object.h +++ b/src/objson/object.h @@ -26,7 +26,7 @@ GNU General Public License for more details. #include #include -#include "utils.h" +#include "opensrf/utils.h" /* json object types */ #define JSON_HASH 0 diff --git a/src/perlmods/OpenSRF/Utils/Config.pm b/src/perlmods/OpenSRF/Utils/Config.pm index 359c255..8e9c398 100755 --- a/src/perlmods/OpenSRF/Utils/Config.pm +++ b/src/perlmods/OpenSRF/Utils/Config.pm @@ -40,7 +40,7 @@ sub new { } 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); } @@ -421,11 +421,11 @@ sub load_config { =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. diff --git a/src/ports/strn_compat/Makefile b/src/ports/strn_compat/Makefile new file mode 100644 index 0000000..1398045 --- /dev/null +++ b/src/ports/strn_compat/Makefile @@ -0,0 +1,20 @@ +# 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 + diff --git a/src/ports/strn_compat/strndup.c b/src/ports/strn_compat/strndup.c new file mode 100644 index 0000000..10b49fd --- /dev/null +++ b/src/ports/strn_compat/strndup.c @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2007 Albert Lee . + * + * 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 +#include + +#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; +} diff --git a/src/ports/strn_compat/strndup.h b/src/ports/strn_compat/strndup.h new file mode 100644 index 0000000..be91f5f --- /dev/null +++ b/src/ports/strn_compat/strndup.h @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2007 Albert Lee . + * + * 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); + diff --git a/src/ports/strn_compat/strnlen.c b/src/ports/strn_compat/strnlen.c new file mode 100644 index 0000000..81a6f17 --- /dev/null +++ b/src/ports/strn_compat/strnlen.c @@ -0,0 +1,56 @@ +/* + * 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 + +/* + * 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); +} diff --git a/src/ports/strn_compat/strnlen.h b/src/ports/strn_compat/strnlen.h new file mode 100644 index 0000000..181780a --- /dev/null +++ b/src/ports/strn_compat/strnlen.h @@ -0,0 +1,26 @@ +/* + * 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); + diff --git a/src/python/osrf/gateway.py b/src/python/osrf/gateway.py new file mode 100644 index 0000000..3a6efaf --- /dev/null +++ b/src/python/osrf/gateway.py @@ -0,0 +1,136 @@ +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)) + + + + + diff --git a/src/python/osrf/json.py b/src/python/osrf/json.py index 826e6b9..1b73e37 100644 --- a/src/python/osrf/json.py +++ b/src/python/osrf/json.py @@ -14,228 +14,222 @@ # ----------------------------------------------------------------------- -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. 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. 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 - + diff --git a/src/python/osrf/net_obj.py b/src/python/osrf/net_obj.py new file mode 100644 index 0000000..1dafa1e --- /dev/null +++ b/src/python/osrf/net_obj.py @@ -0,0 +1,127 @@ +# ----------------------------------------------------------------------- +# 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. 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; + + + + diff --git a/src/python/osrf/ses.py b/src/python/osrf/ses.py index 2fbb502..f1c6c38 100644 --- a/src/python/osrf/ses.py +++ b/src/python/osrf/ses.py @@ -14,6 +14,7 @@ # ----------------------------------------------------------------------- from osrf.json import * +from osrf.net_obj import * from osrf.conf import osrfConfigValue from osrf.net import osrfNetworkMessage, osrfGetNetworkHandle from osrf.log import * diff --git a/src/python/osrf/utils.py b/src/python/osrf/utils.py index 1d9d7aa..fe637f1 100644 --- a/src/python/osrf/utils.py +++ b/src/python/osrf/utils.py @@ -1,116 +1,100 @@ -# ----------------------------------------------------------------------- -# Copyright (C) 2007 Georgia Public Library Service -# Bill Erickson -# -# 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 - + diff --git a/src/utils/log.c b/src/utils/log.c index be2abe0..3adb8b1 100644 --- a/src/utils/log.c +++ b/src/utils/log.c @@ -61,7 +61,7 @@ void osrfLogSetIsClient(int is) { /* 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; } @@ -177,11 +177,11 @@ void _osrfLogDetail( int level, const char* filename, int line, char* msg ) { 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 ); } @@ -205,14 +205,14 @@ void _osrfLogToFile( char* 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)); - + } diff --git a/src/utils/socket_bundle.c b/src/utils/socket_bundle.c index 5441adf..4356ef6 100644 --- a/src/utils/socket_bundle.c +++ b/src/utils/socket_bundle.c @@ -1,5 +1,19 @@ #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 -------------------------------------------------------------------- */ @@ -38,8 +52,9 @@ int main(int argc, char* argv[]) { /* -------------------------------------------------------------------- */ - -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; @@ -72,10 +87,11 @@ int socket_open_tcp_server(socket_manager* mgr, int port, char* listen_ip) { 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; } @@ -89,13 +105,17 @@ int socket_open_tcp_server(socket_manager* mgr, int port, char* listen_ip) { 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; } @@ -110,24 +130,30 @@ int socket_open_unix_server(socket_manager* mgr, char* path) { 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; } @@ -154,8 +180,9 @@ int socket_open_udp_server( 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; } @@ -164,8 +191,10 @@ int socket_open_udp_server( 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; } @@ -183,8 +212,10 @@ int socket_open_tcp_client(socket_manager* mgr, int port, char* dest_addr) { // ------------------------------------------------------------------ // 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; } @@ -196,8 +227,10 @@ int socket_open_tcp_client(socket_manager* mgr, int port, char* dest_addr) { // ------------------------------------------------------------------ // 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; } @@ -221,17 +254,21 @@ int socket_open_tcp_client(socket_manager* mgr, int port, char* dest_addr) { // ------------------------------------------------------------------ // 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 ); @@ -247,8 +284,10 @@ int socket_open_udp_client( 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; } @@ -257,8 +296,9 @@ int socket_open_udp_client( 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; } @@ -266,8 +306,9 @@ int socket_open_udp_client( 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; } @@ -282,8 +323,9 @@ int socket_open_unix_client(socket_manager* mgr, char* sock_path) { 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; } @@ -292,8 +334,10 @@ int socket_open_unix_client(socket_manager* mgr, char* sock_path) { 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; } @@ -303,9 +347,8 @@ int socket_open_unix_client(socket_manager* mgr, char* sock_path) { } - /* 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) { @@ -317,7 +360,7 @@ socket_node* socket_find_node(socket_manager* mgr, int sock_fd) { } /* 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; @@ -349,7 +392,6 @@ void socket_remove_node(socket_manager* mgr, int sock_fd) { } - void _socket_print_list(socket_manager* mgr) { if(mgr == NULL) return; socket_node* node = mgr->socket; @@ -367,16 +409,18 @@ int socket_send(int sock_fd, const char* data) { 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; } @@ -384,9 +428,13 @@ int _socket_send(int sock_fd, const char* data, int flags) { } -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); +//} /* @@ -408,11 +456,13 @@ int socket_send_timeout( int sock_fd, const char* data, int usecs ) { 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; } @@ -450,6 +500,7 @@ int socket_wait(socket_manager* mgr, int timeout, int sock_fd) { struct timeval tv; tv.tv_sec = timeout; tv.tv_usec = 0; + errno = 0; if( timeout < 0 ) { @@ -475,7 +526,7 @@ int socket_wait(socket_manager* mgr, int timeout, int sock_fd) { 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; } @@ -496,21 +547,20 @@ int socket_wait_all(socket_manager* mgr, int timeout) { 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; } } @@ -519,9 +569,14 @@ int socket_wait_all(socket_manager* mgr, int timeout) { 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; @@ -584,7 +639,8 @@ int _socket_route_data( } -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; @@ -606,13 +662,15 @@ int _socket_route_data_id( socket_manager* mgr, int sock_id) { } -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; } @@ -629,7 +687,7 @@ int _socket_handle_new_client(socket_manager* mgr, socket_node* node) { } -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]; @@ -639,7 +697,7 @@ int _socket_handle_client_data(socket_manager* mgr, socket_node* node) { 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); @@ -648,12 +706,13 @@ int _socket_handle_client_data(socket_manager* mgr, socket_node* node) { 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 */ @@ -681,3 +740,4 @@ void socket_manager_free(socket_manager* mgr) { free(mgr); } + diff --git a/src/utils/socket_bundle.h b/src/utils/socket_bundle.h index d1f5fd7..28a5405 100644 --- a/src/utils/socket_bundle.h +++ b/src/utils/socket_bundle.h @@ -34,9 +34,6 @@ #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 { @@ -87,26 +84,9 @@ int socket_open_unix_client(socket_manager*, char* sock_path); 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 ); @@ -115,11 +95,6 @@ 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); @@ -129,24 +104,9 @@ 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 diff --git a/src/utils/utils.c b/src/utils/utils.c index bdeaa96..47b3d2f 100644 --- a/src/utils/utils.c +++ b/src/utils/utils.c @@ -25,29 +25,37 @@ inline void* safe_malloc( int size ) { 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 ); } @@ -65,17 +73,14 @@ int set_fl( int fd, int flags ) { 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; } @@ -83,17 +88,14 @@ int clr_fl( int fd, int flags ) { 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; } @@ -214,6 +216,18 @@ int buffer_reset( growing_buffer *gb){ 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; diff --git a/src/utils/utils.h b/src/utils/utils.h index 671650f..66acb74 100644 --- a/src/utils/utils.h +++ b/src/utils/utils.h @@ -34,12 +34,14 @@ GNU General Public License for more details. #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) \ @@ -175,6 +177,7 @@ int buffer_add(growing_buffer* gb, char* c); 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); diff --git a/src/utils/xml_utils.c b/src/utils/xml_utils.c index a33c36c..ef631e4 100644 --- a/src/utils/xml_utils.c +++ b/src/utils/xml_utils.c @@ -48,10 +48,16 @@ jsonObject* _xmlToJSON(xmlNodePtr node, jsonObject* obj) { } 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;