--- /dev/null
+include Makefile.inc
+
+SUFFIXES = .T
+
+VPATH=${interface}
+AT3=perl -I${lbconfig} ${lbproject}/at3
+
+STAGETO=${stageinc}/${globalprefix}/${lbprefix}
+STATIC_H=consumer.h context.h dump.h load.h notification.h notifid.h purge.h
+GEN_H=events.h jobstat.h producer.h
+
+all stage: stage-gen stage-static
+compile: generate
+
+stage-static:
+ -mkdir -p ${STAGETO}
+ cd ${interface} && install -m 644 ${STATIC_H} ${STAGETO}
+
+stage-gen: generate
+ -mkdir -p ${STAGETO}
+ install -m 644 ${GEN_H} ${STAGETO}
+
+generate: ${GEN_H}
+
+check:
+ @echo No unit test required for interface-only module.
+
+%.h: %.h.T
+ rm -f $@
+ ${AT3} $< >$@ || rm -f $@
+ chmod -w $@ >/dev/null
+
+
--- /dev/null
+<?xml version="1.0" encoding="UTF-8" ?>
+
+<project name="lb" default="dist">
+
+ <import file="../org.glite/project/baseline.properties.xml" />
+ <import file="./project/properties.xml"/>
+ <import file="${subsystem.properties.file}"/>
+ <import file="${global.properties.file}" />
+
+ <property file="${user.dependencies.file}"/>
+ <property file="${component.dependencies.file}" />
+ <property file="${subsystem.dependencies.file}" />
+ <property file="${global.dependencies.file}"/>
+
+ <import file="${subsystem.taskdefs.file}" />
+ <import file="${global.taskdefs.file}" />
+
+ <import file="${global.targets-external-dependencies.file}"/>
+ <import file="${global.targets-make.file}" />
+
+ <property file="${module.version.file}"/>
+
+ <target name="localinit"
+ description="Module specific initialization tasks">
+ <antcall target="lbmakefiles"/>
+ </target>
+
+ <target name="localcompile"
+ description="Module specific compile tasks">
+ </target>
+
+ <target name="localclean"
+ description="Module specific cleaning tasks">
+ </target>
+
+</project>
--- /dev/null
+#ifndef __EDG_WORKLOAD_LOGGING_CLIENT_CONSUMER_H__
+#define __EDG_WORKLOAD_LOGGING_CLIENT_CONSUMER_H__
+
+/*!
+ * \file client/consumer.h (lbapi.h originaly)
+ * \brief L&B consumer API
+ *
+ * General rules:
+ * - functions return 0 on success, nonzero on error, errror details can
+ * be found via edg_wll_ErrorCode()
+ * - OUT are ** types, functions malloc()-ate objects and fill in the pointer
+ * pointed to by the OUT argument
+ * - returned lists of pointers are NULL-terminated malloc()-ed arrays
+ * - edg_wll_Query + wrapper terminate arrays with EDG_WLL_EVENT_UNDEF event
+ * - OUT is NULL if the list is empty
+ */
+
+#ident "$Header$"
+
+#include "glite/wms/jobid/cjobid.h"
+#include "glite/lb/context.h"
+#include "glite/lb/events.h"
+#include "glite/lb/jobstat.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*!
+ * Predefined types for query attributes
+ */
+typedef enum _edg_wll_QueryAttr{
+ EDG_WLL_QUERY_ATTR_UNDEF=0, /**< Not-defined value, used to terminate lists etc. */
+ EDG_WLL_QUERY_ATTR_JOBID, /**< Job Id \see _edg_wll_QueryRec */
+ EDG_WLL_QUERY_ATTR_OWNER, /**< Job owner \see _edg_wll_QueryRec */
+ EDG_WLL_QUERY_ATTR_STATUS, /**< Current job status */
+ EDG_WLL_QUERY_ATTR_LOCATION, /**< Where is the job processed */
+ EDG_WLL_QUERY_ATTR_DESTINATION, /**< Destination CE */
+ EDG_WLL_QUERY_ATTR_DONECODE, /**< Minor done status (OK,fail,cancel) */
+ EDG_WLL_QUERY_ATTR_USERTAG, /**< User tag */
+ EDG_WLL_QUERY_ATTR_TIME, /**< Timestamp \see _edg_wll_QueryRec */
+ EDG_WLL_QUERY_ATTR_LEVEL, /**< Logging level (see "dglog.h") * \see _edg_wll_QueryRec */
+ EDG_WLL_QUERY_ATTR_HOST, /**< Where the event was generated */
+ EDG_WLL_QUERY_ATTR_SOURCE, /**< Source component */
+ EDG_WLL_QUERY_ATTR_INSTANCE, /**< Instance of the source component */
+ EDG_WLL_QUERY_ATTR_EVENT_TYPE, /**< Event type \see _edg_wll_QueryRec */
+ EDG_WLL_QUERY_ATTR_CHKPT_TAG, /**< Checkpoint tag */
+ EDG_WLL_QUERY_ATTR_RESUBMITTED, /**< Job was resubmitted */
+ EDG_WLL_QUERY_ATTR_PARENT, /**< Job was resubmitted */
+ EDG_WLL_QUERY_ATTR_EXITCODE, /**< Unix exit code */
+ EDG_WLL_QUERY_ATTR__LAST
+/* if adding new attribute, add conversion string to common/xml_conversions.c too !! */
+} edg_wll_QueryAttr;
+
+
+/*!
+ * Predefined types for query operands
+ */
+typedef enum _edg_wll_QueryOp{
+ EDG_WLL_QUERY_OP_EQUAL, /**< attribute is equal to the operand value \see _edg_wll_QueryRec */
+ EDG_WLL_QUERY_OP_LESS, /**< attribute is grater than the operand value \see _edg_wll_QueryRec */
+ EDG_WLL_QUERY_OP_GREATER, /**< attribute is less than the operand value \see _edg_wll_QueryRec */
+ EDG_WLL_QUERY_OP_WITHIN, /**< attribute is in given interval \see _edg_wll_QueryRec */
+ EDG_WLL_QUERY_OP_UNEQUAL, /**< attribute is not equal to the operand value \see _edg_wll_QueryRec */
+} edg_wll_QueryOp;
+
+
+/*!
+ * Single query condition for edg_wll_Query().
+ * Those records are composed to form an SQL \a where clause
+ * when processed at the L&B server
+ */
+typedef struct _edg_wll_QueryRec {
+ edg_wll_QueryAttr attr; /**< attribute to query */
+ edg_wll_QueryOp op; /**< query operation */
+
+/**
+ * Specification of attribute to query
+ */
+ union {
+ char * tag; /**< user tag name */
+ edg_wll_JobStatCode state; /**< job status code */
+ } attr_id;
+/**
+ * Query operand.
+ * The appropriate type is uniquely defined by the attr member
+ */
+ union {
+ int i; /**< integer query attribute value */
+ char *c; /**< character query attribute value */
+ struct timeval t; /**< time query attribute value */
+ edg_wlc_JobId j; /**< JobId query attribute value */
+ } value, value2;
+} edg_wll_QueryRec;
+
+/************************************************
+ * API FUNCTION DECLARATIONS *
+ */
+
+
+#ifdef CLIENT_SBIN_PROG
+extern int edg_wll_http_send_recv(
+ edg_wll_Context,
+ char *, const char * const *, char *,
+ char **,char ***,char **
+);
+
+extern int http_check_status(
+ edg_wll_Context,
+ char *,
+ char **
+);
+
+extern int set_server_name_and_port(
+ edg_wll_Context,
+ const edg_wll_QueryRec **
+);
+
+#endif
+
+/**
+ * \name Server querying
+ *
+ *@{
+ */
+
+/**
+ * General query on events.
+ * Return events satysfying all conditions
+ * query records represent conditions in the form
+ * \a attr \a op \a value eg. time > 87654321.
+ * \see edg_wll_QueryRec
+ *
+ * \param context IN: context to work with
+ * \param job_conditions IN: query conditions (ANDed) on current job status, null (i.e. ATTR_UNDEF) terminated list. NULL means empty list, i.e. always TRUE
+ * \param event_conditions: conditions on events, null terminated list, NULL means empty list, i.e. always TRUE
+ * \param events OUT: list of matching events
+ */
+int edg_wll_QueryEvents(
+ edg_wll_Context context,
+ const edg_wll_QueryRec * job_conditions,
+ const edg_wll_QueryRec * event_conditions,
+ edg_wll_Event ** events
+);
+
+int edg_wll_QueryEventsExt(
+ edg_wll_Context context,
+ const edg_wll_QueryRec ** job_conditions,
+ const edg_wll_QueryRec ** event_conditions,
+ edg_wll_Event ** events
+);
+
+/**
+ * General query on jobs.
+ * Return jobs (and possibly their states) for which an event satisfying the conditions
+ * exists.
+ * \see edg_wll_QueryEvents
+ * \param context IN: context to work with
+ * \param conditions IN: query records (ANDed), null (i.e. EDG_WLL_ATTR_UNDEF) terminated list
+ * \param flags IN: additional status fields to retrieve (\see edg_wll_JobStatus)
+ * \param jobs OUT: list of job ids. May be NULL.
+ * \param states OUT: list of corresponding states (returned only if not NULL)
+ */
+int edg_wll_QueryJobs(
+ edg_wll_Context context,
+ const edg_wll_QueryRec * conditions,
+ int flags,
+ edg_wlc_JobId ** jobs,
+ edg_wll_JobStat ** states
+);
+
+int edg_wll_QueryJobsExt(
+ edg_wll_Context context,
+ const edg_wll_QueryRec ** conditions,
+ int flags,
+ edg_wlc_JobId ** jobs,
+ edg_wll_JobStat ** states
+);
+
+/**
+ * Bitmasks for edg_wll_JobStatus() flags argument.
+ * Settings these flags causes the status calls to retrieve additional
+ * information.
+ */
+#define EDG_WLL_STAT_CLASSADS 1 /**< various job description fields */
+#define EDG_WLL_STAT_CHILDREN 2 /**< list of subjob JobId's */
+#define EDG_WLL_STAT_CHILDSTAT 4 /**< apply the flags recursively to subjobs */
+/* starting from bit 10 private flags begins - do not add 1024 and more! */
+
+/** Return status of a single job.
+ * \param context IN: context to operate on
+ * \param jobid IN: query this job
+ * \param flags IN: specifies optional status fields to retrieve,
+ * \see EDG_WLL_STAT_CLASSADS, EDG_WLL_STAT_CHILDREN, EDG_WLL_STAT_CHILDSTAT
+ */
+
+int edg_wll_JobStatus(
+ edg_wll_Context context,
+ const edg_wlc_JobId jobid,
+ int flags,
+ edg_wll_JobStat *status
+);
+
+/**
+ * Return all events related to a single job.
+ * Convenience wrapper around edg_wll_Query()
+ * \param context IN: context to work with
+ * \param jobId IN: job to query
+ * \param events OUT: list of events
+ */
+
+int edg_wll_JobLog(
+ edg_wll_Context context,
+ const edg_wlc_JobId jobId,
+ edg_wll_Event ** events
+);
+
+/**
+ * All current user's jobs.
+ * \param context IN: context to work with
+ * \param jobs OUT: list of the user's jobs
+ * \param states OUT: list of the jobs' states
+ */
+int edg_wll_UserJobs(
+ edg_wll_Context context,
+ edg_wlc_JobId ** jobs,
+ edg_wll_JobStat ** states
+);
+
+/**
+ * Server supported indexed attributes
+ * \see DataGrid-01-TEN-0125
+ * \param context IN: context to work with
+ * \param attrs OUT: configured indices (each index is an UNDEF-terminated
+ * array of QueryRec's from which only attr (and attr_id
+ * eventually) are meaningful
+ */
+int edg_wll_GetIndexedAttrs(
+ edg_wll_Context context,
+ edg_wll_QueryRec ***attrs
+);
+
+/**
+ * Retrieve limit on query result size (no. of events or jobs).
+ * FIXME: not implemented.
+ * \see DataGrid-01-TEN-0125
+ * \param context IN: context to work with
+ * \param limit OUT: server imposed limit
+ */
+int edg_wll_GetServerLimit(
+ edg_wll_Context context,
+ int *limit
+);
+
+/**
+ * UI port for the job
+ * \param context IN: context to work with
+ * \param jobId IN: job to query
+ * \param name IN: name of the UI-port
+ * \param host OUT: hostname of port
+ * \param port OUT: port number
+ */
+int edg_wll_QueryListener(
+ edg_wll_Context context,
+ edg_wlc_JobId jobId,
+ const char * name,
+ char ** host,
+ uint16_t * port
+);
+
+/*@}*/
+
+/*
+ * edg_wll_QueryRec manipulation
+ */
+
+/** Free edg_wll_QueryRec internals, not the structure itself */
+void edg_wll_QueryRecFree(edg_wll_QueryRec *);
+
+/**
+ * default and maximal query timeout (in seconds)
+ */
+#define EDG_WLL_QUERY_TIMEOUT_DEFAULT 120
+#define EDG_WLL_QUERY_TIMEOUT_MAX 1800
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __EDG_WORKLOAD_LOGGING_CLIENT_CONSUMER_H__ */
--- /dev/null
+#ifndef _EDG_WORKLOAD_LOGGING_CLIENT_CONTEXT_H
+#define _EDG_WORKLOAD_LOGGING_CLIENT_CONTEXT_H
+
+/**
+ * \file edg/workload/logging/client/context.h
+ * \brief L&B API common context (publicly visible) and related definitions
+ */
+
+#include "glite/wms/common/utilities/exception_codes.h"
+#include "glite/wms/jobid/cjobid.h"
+
+#ident "$Header$"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/** Opaque context type */
+typedef struct _edg_wll_Context *edg_wll_Context;
+
+/** Constants defining the context parameters */
+typedef enum _edg_wll_ContextParam {
+ EDG_WLL_PARAM_HOST, /**< hostname to appear as event orgin */
+ EDG_WLL_PARAM_SOURCE, /**< event source component */
+ EDG_WLL_PARAM_INSTANCE, /**< instance of the source component */
+ EDG_WLL_PARAM_LEVEL, /**< logging level */
+ EDG_WLL_PARAM_DESTINATION, /**< logging destination host */
+ EDG_WLL_PARAM_DESTINATION_PORT, /**< logging destination port */
+ EDG_WLL_PARAM_LOG_TIMEOUT, /**< logging timeout (asynchronous) */
+ EDG_WLL_PARAM_LOG_SYNC_TIMEOUT, /**< logging timeout (synchronous) */
+ EDG_WLL_PARAM_QUERY_SERVER, /**< default server name to query */
+ EDG_WLL_PARAM_QUERY_SERVER_PORT,/**< default server port to query */
+ EDG_WLL_PARAM_QUERY_SERVER_OVERRIDE,/**< host:port parameter setting override even values in jobid (useful for debugging & hacking only) */
+ EDG_WLL_PARAM_QUERY_TIMEOUT, /**< query timeout */
+ EDG_WLL_PARAM_QUERY_JOBS_LIMIT, /**< maximal query jobs result size */
+ EDG_WLL_PARAM_QUERY_EVENTS_LIMIT,/**< maximal query events result size */
+ EDG_WLL_PARAM_QUERY_RESULTS, /**< maximal query result size */
+ EDG_WLL_PARAM_QUERY_CONNECTIONS,/**< maximal number of open connections in ctx->connPoll */
+ EDG_WLL_PARAM_NOTIF_SERVER, /**< default notification server name */
+ EDG_WLL_PARAM_NOTIF_SERVER_PORT,/**< default notification server port */
+ EDG_WLL_PARAM_NOTIF_TIMEOUT, /**< notif timeout */
+ EDG_WLL_PARAM_X509_PROXY, /**< proxy file to use for authentication */
+ EDG_WLL_PARAM_X509_KEY, /**< key file to use for authentication */
+ EDG_WLL_PARAM_X509_CERT, /**< certificate file to use for authentication */
+ EDG_WLL_PARAM__LAST, /**< marker, LB internal use only */
+} edg_wll_ContextParam;
+
+/** sets returned query results */
+typedef enum _edg_wll_QueryResults {
+ EDG_WLL_QUERYRES_UNDEF, /* uninitialized value */
+ EDG_WLL_QUERYRES_NONE,
+ EDG_WLL_QUERYRES_ALL,
+ EDG_WLL_QUERYRES_LIMITED,
+ EDG_WLL_QUERYRES__LAST /* marker, for internal use only */
+} edg_wll_QueryResults;
+
+/** identification of logging component */
+typedef enum _edg_wll_Source {
+ EDG_WLL_SOURCE_NONE, /* uninitialized value */
+ EDG_WLL_SOURCE_USER_INTERFACE,
+ EDG_WLL_SOURCE_NETWORK_SERVER,
+ EDG_WLL_SOURCE_WORKLOAD_MANAGER,
+ EDG_WLL_SOURCE_BIG_HELPER,
+ EDG_WLL_SOURCE_JOB_SUBMISSION,
+ EDG_WLL_SOURCE_LOG_MONITOR,
+ EDG_WLL_SOURCE_LRMS,
+ EDG_WLL_SOURCE_APPLICATION,
+ EDG_WLL_SOURCE__LAST /* marker, for internal use only */
+} edg_wll_Source;
+
+
+/** Allocate an initialize a new context object.
+ * \param context OUT returned context
+ * \return 0 on success, ENOMEM if malloc() fails
+ */
+int edg_wll_InitContext(edg_wll_Context *context);
+
+/** Destroy and free context object.
+ * Also performs necessary cleanup (closing connections etc.)
+ * \param context IN context to free
+ */
+void edg_wll_FreeContext(edg_wll_Context context);
+
+/** Set a context parameter.
+ * \param context INOUT context to work with
+ * \param param IN parameter to set
+ * \param ... IN value to set (if NULL or 0, default is used)
+ * \retval 0 success
+ * \retval EINVAL param is not a valid parameter, or invalid value
+ */
+int edg_wll_SetParam(
+ edg_wll_Context context,
+ edg_wll_ContextParam param,
+ ...
+);
+
+struct timeval; /* gcc, shut up! */
+
+int edg_wll_SetParamInt(edg_wll_Context,edg_wll_ContextParam,int);
+int edg_wll_SetParamString(edg_wll_Context,edg_wll_ContextParam,const char *);
+int edg_wll_SetParamTime(edg_wll_Context,edg_wll_ContextParam,const struct timeval *);
+
+/** Get current parameter value.
+ * \param context INOUT context to work with
+ * \param param IN parameter to retrieve
+ * \param ... OUT pointer to output variable
+ * \retval 0 success
+ * \retval EINVAL param is not a valid parameter
+ */
+int edg_wll_GetParam(
+ edg_wll_Context context,
+ edg_wll_ContextParam param,
+ ...
+);
+
+
+/**
+ * L&B subsystem specific error codes.
+ * Besides them L&B functions return standard \a errno codes in their usual
+ * meaning.
+ */
+
+/* XXX: cleanup required */
+
+typedef enum _edg_wll_ErrorCode {
+/** Base for L&B specific code. Use the constant from common/ */
+ EDG_WLL_ERROR_BASE = GLITE_WMS_LOGGING_ERROR_BASE,
+ EDG_WLL_ERROR_PARSE_BROKEN_ULM, /**< Parsing ULM line into edg_wll_Event structure */
+ EDG_WLL_ERROR_PARSE_EVENT_UNDEF, /**< Undefined event name */
+ EDG_WLL_ERROR_PARSE_MSG_INCOMPLETE, /**< Incomplete message (missing fields) */
+ EDG_WLL_ERROR_PARSE_KEY_DUPLICITY, /**< Duplicate entry in message */
+ EDG_WLL_ERROR_PARSE_KEY_MISUSE, /**< Entry not allowed for this message type */
+ EDG_WLL_ERROR_PARSE_OK_WITH_EXTRA_FIELDS, /**< Additional, not understood fields found in message.
+ The rest is OK therefore this is not a true error. */
+ EDG_WLL_ERROR_XML_PARSE, /**< Error in parsing XML protocol. */
+ EDG_WLL_ERROR_SERVER_RESPONSE, /**< Generic failure on server. See syslog on the server machine for details. */
+ EDG_WLL_ERROR_JOBID_FORMAT, /**< Malformed jobid */
+ EDG_WLL_ERROR_DB_CALL, /**< Failure of underlying database engine.
+ See errDesc returned by edg_wll_ErrorCode(). */
+ EDG_WLL_ERROR_URL_FORMAT, /**< Malformed URL */
+ EDG_WLL_ERROR_MD5_CLASH, /**< MD5 hash same for different strings. Very unlikely :-). */
+ EDG_WLL_ERROR_SSL, /**< Generic SSL error. See errDesc returned by edg_wll_Error(). */
+ EDG_WLL_ERROR_DNS, /**< DNS resolver error. See errDesc returned by edg_wll_Error(). */
+ EDG_WLL_ERROR_NOJOBID, /**< Attmepted call requires calling edg_wll_SetLoggingJob() first. */
+ EDG_WLL_ERROR_NOINDEX, /**< Query does not contain any conidion on indexed attribute. */
+ EDG_WLL_IL_PROTO, /**< Interlogger to lbserver communication protocol error. */
+ EDG_WLL_IL_SYS, /**< Interlogger internal error. */
+ EDG_WLL_IL_EVENTS_WAITING, /**< Interlogger still has events pending delivery. */
+} edg_wll_ErrorCode;
+
+/**
+ * Retrieve error details on recent API call
+ * \param context IN: context to work with
+ * \param errText OUT: standard error text
+ * (may be NULL - no text returned)
+ * \param errDesc OUT: additional error description
+ * (may be NULL - no text returned)
+ * \return Error code of the recent error
+ */
+
+int edg_wll_Error(
+ edg_wll_Context context,
+ char **errText,
+ char **eddDesc
+);
+
+/** Convert source code to printable string
+ */
+char * edg_wll_SourceToString(edg_wll_Source src);
+
+/** Convert name to source code
+ * \return Matching code or EDG_WLL_SOURCE_NONE
+ */
+edg_wll_Source edg_wll_StringToSource(const char *name);
+
+/** Convert Query result code to printable string
+ */
+char * edg_wll_QResultToString(edg_wll_QueryResults res);
+
+/** Convert name to Query result code
+ * \return Matching code or EDG_WLL_SOURCE_NONE
+ */
+edg_wll_QueryResults edg_wll_StringToQResult(const char *name);
+
+/**
+ * type of sequence code (used when setting to the context)
+ */
+#define EDG_WLL_SEQ_NORMAL 1
+#define EDG_WLL_SEQ_DUPLICATE 11
+
+/**
+ * initial sequence code for BigHelper
+ */
+
+#define EDG_WLL_SEQ_BIGHELPER_INITIAL "UI=2:NS=0:WM=0:BH=1:JSS=0:LM=0:LRMS=0:APP=0"
+
+/** Retrieve current sequence code from the context */
+char * edg_wll_GetSequenceCode(
+ const edg_wll_Context context
+);
+
+/**
+ * retrieve the current logging JobId from the context
+ */
+int edg_wll_GetLoggingJob(
+ const edg_wll_Context context,
+ edg_wlc_JobId *jobid_out
+);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
--- /dev/null
+#ifndef __EDG_WORKLOAD_LOGGING_CLIENT_DUMP_H__
+#define __EDG_WORKLOAD_LOGGING_CLIENT_DUMP_H__
+
+#ident "$Header$"
+
+#define EDG_WLL_DUMP_NOW -1
+#define EDG_WLL_DUMP_LAST_START -2
+#define EDG_WLL_DUMP_LAST_END -3
+/* if adding new attribute, add conversion string to common/xml_conversions.c too !! */
+
+typedef struct {
+ time_t from,to;
+} edg_wll_DumpRequest;
+
+typedef struct {
+ char *server_file;
+ time_t from,to;
+} edg_wll_DumpResult;
+
+/** Dump events in a given time interval
+ */
+
+int edg_wll_DumpEvents(
+ edg_wll_Context,
+ const edg_wll_DumpRequest *,
+ edg_wll_DumpResult *
+);
+
+
+#endif
+
--- /dev/null
+#ifndef __EDG_WORKLOAD_LOGGING_CLIENT_EVENTS_H__
+#define __EDG_WORKLOAD_LOGGING_CLIENT_EVENTS_H__
+
+/**
+ * \file edg/workload/logging/client/events.h
+ * \brief contains definition of event type codes for use both by lbapi.h and dglog.h
+ */
+
+#ident "$Header$"
+/*
+@@@AUTO
+*/
+@@@LANG: C
+
+#include <sys/time.h>
+#include <inttypes.h>
+
+#include "glite/wms/jobid/cjobid.h"
+#include "glite/lb/context.h"
+#include "glite/lb/notifid.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+/**
+ * Predefined type for ULM string
+ */
+typedef char *edg_wll_LogLine;
+
+
+/**
+ * \typedef edg_wll_EventCode
+ * Predefined event types
+ */
+typedef enum _edg_wll_EventCode {
+/** invalid code, e.g. uninitialized variable */
+ EDG_WLL_EVENT_UNDEF = 0,
+@@@{
+for my $e (sort { $event->{order}->{$a} <=> $event->{order}->{$b} }
+ $event->getTypes) {
+ my $u = uc $e;
+ my $c = getTypeComment $event $e;
+ gen "\tEDG_WLL_EVENT_$u,\t/**< $c */\n";
+}
+@@@}
+ EDG_WLL_EVENT__LAST, /**< last currently supported event code */
+} edg_wll_EventCode;
+
+/**
+ * \fn edg_wll_EventCode edg_wll_StringToEvent(char *name)
+ * \param name a string event name (e.g. "JobTransfer")
+ * \return corresponding numeric code (edg_wll_EventCode)
+ * \brief convert a string event name to the corresponding numeric code
+ */
+
+extern edg_wll_EventCode edg_wll_StringToEvent(char *);
+
+/**
+ * \fn char *edg_wll_EventToString(edg_wll_EventCode event)
+ * \param event an event numeric code (edg_wll_EventCode)
+ * \return corresponding string (e.g. "JobTransfer")
+ * \brief convert an event numeric code to the corresponding string
+ */
+
+extern char *edg_wll_EventToString(edg_wll_EventCode);
+
+
+/**
+ * \typedef edg_wll_KeyNameCode
+ * Predefined ULM key types
+ */
+typedef enum _edg_wll_KeyNameCode {
+ UNDEFINED, /**< undefined */
+ EDG_WLL_EVNT, /**< event type */
+@@@{
+selectType $event '_common_';
+for ($event->getFieldsOrdered) {
+ my $f = selectField $event $_;
+ my $fn = getName $f 'ULM';
+ my $fnu = uc $fn;
+ my $c = $f->{comment};
+ if (hasAlias $f 'ULM') {
+ gen "\tULM\_$fnu,\t\t/**< $c */\n";
+ } else {
+ gen "\tEDG_WLL\_COMMON\_$fnu,\t\t/**< $c */\n";
+ }
+}
+for my $t (sort { $event->{order}->{$a} <=> $event->{order}->{$b} }
+ $event->getTypes) {
+ my $tu = uc $t;
+ selectType $event $t;
+ for ($event->getFieldsOrdered) {
+ my $f = selectField $event $_;
+ my $fnu = uc $f->{name};
+ my $c = $f->{comment};
+ gen "\tEDG_WLL\_$tu\_$fnu,\t/**< $c */\n";
+ }
+}
+@@@}
+ EDG_WLL_INTERNAL_TYPE, /**< internal message type */
+} edg_wll_KeyNameCode;
+
+/**
+ * \fn edg_wll_KeyNameCode edg_wll_StringToKeyName(char *name)
+ * \param name a string ULM key name (e.g. "DG.JOB.TRANSFER.DEST")
+ * \return corresponding numeric code (edg_wll_KeyNameCode)
+ * \brief convert a string ULM key name to the corresponding numeric code
+ */
+
+extern edg_wll_KeyNameCode edg_wll_StringToKeyName(char *);
+
+/**
+ * \fn char *edg_wll_KeyNameToString(edg_wll_KeyNameCode key)
+ * \param key a ULM key name numeric code (edg_wll_KeyNameCode)
+ * \return corresponding string (e.g. "DG.JOB.TRANSFER.DEST")
+ * \brief convert a ULM key name numeric code to the corresponding string
+ */
+
+extern char *edg_wll_KeyNameToString(edg_wll_KeyNameCode);
+
+
+/**
+ * Predefined _code_ types and
+ * related StringTo_code and _code_ToString function prototypes
+ */
+@@@{
+$indent = "\t";
+selectType $event '_common_';
+for ($event->getFieldsOrdered) {
+ my $f = selectField $event $_;
+ if ($f->{codes}) {
+ my $fn = ucfirst($f->{name});
+ my $fnu = uc $fn;
+ my $c = "${fn}"; # new code
+ my $enum = "enum edg_wll\_$c"; # new enum name
+
+# enum
+ gen qq{
+/**
+ * \\enum $enum
+ * $fn codes
+ */
+$enum \{
+};
+ gen $indent."EDG_WLL_${fnu}_UNDEFINED,\t/**< undefined code */ \n";
+ for (@{$f->{codes}}) {
+ gen $indent."EDG_WLL_${fnu}_$_->{name},\t/**< $_->{comment} */ \n";
+ }
+ gen "};\n";
+
+# function StringTo:
+ gen qq{
+/**
+ * \\fn $enum edg_wll_StringTo${c}(char *name);
+ * \\param name a string representing $fn code (e.g. \"${$f->{codes}}[1]->{name}\")
+ * \\return corresponding numeric code ($enum)
+ * \\brief converts a string $fn code to corresponding numeric code
+ */
+extern $enum edg_wll_StringTo${c}(char *name);
+};
+
+# function ToString:
+ gen qq{
+/**
+ * \\fn char *edg_wll\_${c}ToString($enum code);
+ * \\param code a $fn numeric code ($enum)
+ * \\return corresponding string (e.g. \"${$f->{codes}}[1]->{name}\")
+ * \\brief converts a $fn numeric code to corresponding string
+ */
+extern char *edg_wll\_${c}ToString($enum code);
+\n};
+ }
+}
+for my $t (sort { $event->{order}->{$a} <=> $event->{order}->{$b} }
+ $event->getTypes) {
+ my $tu = uc $t . '_';
+ selectType $event $t;
+ for ($event->getFieldsOrdered) {
+ my $f = selectField $event $_;
+ if ($f->{codes}) {
+ my $fn = ucfirst($f->{name});
+ my $c = "$t${fn}"; # new code
+ my $enum = "enum edg_wll\_$c"; # new enum name
+
+# enum
+ gen qq{
+/**
+ * \\enum $enum
+ * $fn codes of the $t event
+ */
+$enum \{
+};
+ gen $indent."EDG_WLL_${tu}UNDEFINED,\t/**< undefined code */ \n";
+ for (@{$f->{codes}}) {
+ gen $indent."EDG_WLL_$tu$_->{name},\t/**< $_->{comment} */ \n";
+ }
+ gen "};\n";
+
+# function StringTo:
+ gen qq{
+/**
+ * \\fn $enum edg_wll_StringTo${c}(char *name);
+ * \\param name a string representing $t $fn code (e.g. \"${$f->{codes}}[1]->{name}\")
+ * \\return corresponding numeric code ($enum)
+ * \\brief converts a string $t $fn code to corresponding numeric code
+ */
+extern $enum edg_wll_StringTo${c}(char *name);
+};
+
+# function ToString:
+ gen qq{
+/**
+ * \\fn char *edg_wll\_${c}ToString($enum code);
+ * \\param code a $t $fn numeric code ($enum)
+ * \\return corresponding string (e.g. \"${$f->{codes}}[1]->{name}\")
+ * \\brief converts a $t $fn numeric code to corresponding string
+ */
+extern char *edg_wll\_${c}ToString($enum code);
+\n};
+ }
+ }
+}
+@@@}
+
+
+/**
+ * common fields of all event types:
+ */
+
+@@@{
+$indent = "\t";
+gen "#define _EDG_WLL_EVENT_COMMON \\\n";
+gen $indent."edg_wll_EventCode\t\ttype;\\\n";
+selectType $event '_common_';
+for ($event->getFieldsOrdered) {
+ my $f = selectField $event $_;
+ my $fn = $f->{name};
+ my $tn = $f->getType;
+ gen $indent."$tn\t\t$fn;\t\\\n";
+}
+gen "\n";
+@@@}
+
+typedef struct _edg_wll_AnyEvent {
+_EDG_WLL_EVENT_COMMON
+} edg_wll_AnyEvent;
+
+
+/**
+ * Event types specific structures:
+ */
+@@@{
+$indent = "\t";
+for my $t (sort { $event->{order}->{$a} <=> $event->{order}->{$b} }
+ $event->getTypes) {
+ my $tu = uc $t;
+ my $s = "edg_wll_${t}Event";
+# typedef struct
+ gen qq{
+/**
+* \\typedef $s
+* structure definition for $t event
+*/
+typedef struct \_$s \{
+_EDG_WLL_EVENT_COMMON
+};
+ selectType $event $t;
+ for ($event->getFieldsOrdered) {
+ my $f = selectField $event $_;
+ my $fn = $f->{name};
+ my $fnu = ucfirst $fn;
+ my $c = $f->{comment};
+ my $tn;
+ if ($f->{codes}) {
+ $tn = "enum edg_wll\_$t${fnu}";
+ } else {
+ $tn = $f->getType;
+ }
+ gen $indent."$tn\t$fn;\t/**< $c */\n";
+ }
+ gen "\} $s;\n";
+}
+@@@}
+
+#undef _EDG_WLL_EVENT_COMMON
+
+
+/**
+ * \union edg_wll_Event
+ * \brief All event types union
+ */
+typedef union _edg_wll_Event {
+ edg_wll_EventCode type; /* it is probably never used */
+ edg_wll_AnyEvent any;
+@@@{
+$indent = "\t";
+for my $t (sort { $event->{order}->{$a} <=> $event->{order}->{$b} }
+ $event->getTypes) {
+ my $tl = lcfirst $t;
+ gen $indent."edg_wll_${t}Event\t${tl};\n";
+}
+@@@}
+} edg_wll_Event;
+
+
+/**
+ * Initialise an event structure
+ * \return pointer to initialised event structure
+ */
+extern edg_wll_Event *edg_wll_InitEvent(edg_wll_EventCode eventcode);
+
+
+/**
+ * Free the contents of event structure
+ * \param IN event structure to be freed
+ * \warning As event structures are likely to be allocated in arrays,
+ * the structure itself is not freed.
+ * Its the responsibility of the caller to call free(event)
+ * if appropriate.
+ */
+void edg_wll_FreeEvent(
+ edg_wll_Event * event
+);
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __EDG_WORKLOAD_LOGGING_CLIENT_EVENTS_H__ */
--- /dev/null
+#ifndef __EDG_WORKLOAD_LOGGING_CLIENT_JOBSTAT_H__
+#define __EDG_WORKLOAD_LOGGING_CLIENT_JOBSTAT_H__
+
+/*
+@@@AUTO
+*/
+
+/*!
+ * \file client/jobstat.h
+ * \brief edg_wll_JobStat definition and related stuff
+ */
+
+#ident "$Header$"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * Miscelaneous job status numeric codes
+ */
+
+@@@{
+ for my $n ($status->getAllFieldsOrdered) {
+# XXX: we've got only _common_ in jobStatus, no clash possible
+ my $f = selectField $status $n;
+ if ($f->{codes}) {
+ my $n = ucfirst getName $f;
+ gen qq{
+!enum edg_wll_Stat$n \{
+};
+ for (@{$f->{codes}}) {
+ my $uc = uc $_->{name};
+ gen qq{
+! EDG_WLL_STAT_$uc, /**< $_->{comment} */
+};
+ }
+ gen qq{
+!\};
+};
+ }
+ }
+@@@}
+
+
+/*!
+ *
+ * Job status numeric code
+ */
+
+typedef enum _edg_wll_JobStatCode {
+/** Indicates invalid edg_wll_JobStat structure */
+ EDG_WLL_JOB_UNDEF = 0,
+@@@{
+ for my $stat ($status->getTypesOrdered) {
+ my $u = uc $stat;
+ my $c = getTypeComment $status $stat;
+ gen qq{
+! EDG_WLL_JOB_$u, /**< $c */
+};
+ }
+@@@}
+ EDG_WLL_NUMBER_OF_STATCODES /**< Number of meaningful status codes */
+} edg_wll_JobStatCode;
+
+/*!
+ *
+ * Pair tag = value.
+ */
+typedef struct _edg_wll_TagValue {
+ char * tag; /**< User-specified information tag */
+ char * value; /**< Value assigned to user-specified information tag */
+} edg_wll_TagValue;
+
+
+/*!
+ *
+ * Description of the job status.
+ * Returned by the edg_wll_JobStatus() function
+ */
+typedef struct _edg_wll_JobStat {
+ edg_wll_JobStatCode state; /**< status code */
+@@@{
+ for my $n (getAllFieldsOrdered $status) {
+ selectField $status $n;
+ my $f = getField $status;
+ my $type = getType $f;
+ my $name = getName $f;
+ my $fucname = ucfirst $name;
+ $type = "enum edg_wll_Stat$fucname" if $f->{codes};
+ my $comment = getComment $f;
+ gen qq{
+! $type $name; /**< $comment */
+};
+ }
+@@@}
+
+} edg_wll_JobStat;
+
+/**
+ * \name edg_wll_JobStat manipulation
+ */
+
+/*@{*/
+
+/**
+ * Initialize empty status structure.
+ * Fills in the stucture with NULL's or values with no meaning
+ */
+
+extern int edg_wll_InitStatus(edg_wll_JobStat *);
+
+/**
+ * Initialize dest structure and copy source status to this destination
+ */
+
+extern edg_wll_JobStat *edg_wll_CpyStatus(const edg_wll_JobStat *,edg_wll_JobStat *);
+
+/**
+ * Free status structure contents.
+ * \warning The structure itself is not freed.
+ */
+extern void edg_wll_FreeStatus(edg_wll_JobStat *);
+
+/**
+ * Convert string job status to numeric code.
+ */
+extern edg_wll_JobStatCode edg_wll_StringToStat(const char *);
+
+/**
+ * Convert numeric job status code to string representation
+ */
+extern char *edg_wll_StatToString(edg_wll_JobStatCode);
+
+/*@}*/
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __EDG_WORKLOAD_LOGGING_CLIENT_JOBSTAT_H__ */
--- /dev/null
+#ifndef __EDG_WORKLOAD_LOGGING_CLIENT_LOAD_H__
+#define __EDG_WORKLOAD_LOGGING_CLIENT_LOAD_H__
+
+#ident "$Header$"
+
+typedef struct {
+ char *server_file;
+} edg_wll_LoadRequest;
+
+typedef struct {
+ char *server_file;
+ time_t from,to;
+} edg_wll_LoadResult;
+
+/** Load events from a given file into the database
+ * \retval EPERM operation not permitted
+ * \retval ENOENT file not found
+ */
+
+int edg_wll_LoadEvents(
+ edg_wll_Context,
+ const edg_wll_LoadRequest *,
+ edg_wll_LoadResult *
+);
+
+#endif
+
--- /dev/null
+#ifndef __EDG_WORKLOAD_LOGGING_CLIENT_NOTIFICATION_H__
+#define __EDG_WORKLOAD_LOGGING_CLIENT_NOTIFICATION_H__
+
+#ident "$Header$"
+
+#include "glite/wms/jobid/cjobid.h"
+#include "glite/lb/notifid.h"
+#include "glite/lb/context.h"
+#include "glite/lb/consumer.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * default and maximal notif timeout (in seconds)
+ */
+#define EDG_WLL_NOTIF_TIMEOUT_DEFAULT 120
+#define EDG_WLL_NOTIF_TIMEOUT_MAX 1800
+
+
+/** Register for receiving notifications.
+ * Connects to the server specified by EDG_WLL_NOTIF_SERVER context parameter
+ * (temporary workaround, should be resolved by registry in future).
+ * \param conditions: the same conditions as for \see edg_wll_QueryJobsExt.
+ * currently one or more JOBID's are required.
+ * Only a single occurence of a specific attribute is allowed
+ * among ANDed conditions (due to the ability to modify them
+ * further).
+ * \param fd = -1 create or reuse the default listening socket (one per context)
+ * >= 0 non-default listening socket
+ * \param address_override if not NULL, use this address instead of extracting it
+ * from the connection (useful when multiple interfaces are present,
+ * circumventing NAT problems etc.)
+ * \param valid until when the registration is valid (NULL means no interest in
+ * the value
+ * \retval 0 OK
+ * \retval EINVAL restrictions on conditions are not met
+ *
+ */
+int edg_wll_NotifNew(
+ edg_wll_Context context,
+ edg_wll_QueryRec const * const *conditions,
+ int fd,
+ const char *address_override,
+ edg_wll_NotifId *id_out,
+ time_t *valid
+);
+
+
+/** Change the receiving local address.
+ * Report the new address to the server.
+ *
+ * \param fd
+ * \param address_override
+ * \param valid all same as for \see edg_wll_NotifNew
+ */
+
+int edg_wll_NotifBind(
+ edg_wll_Context context,
+ const edg_wll_NotifId id,
+ int fd,
+ const char *address_override,
+ time_t *valid
+);
+
+typedef enum _edg_wll_NotifChangeOp {
+ EDG_WLL_NOTIF_NOOP = 0,
+ EDG_WLL_NOTIF_REPLACE,
+ EDG_WLL_NOTIF_ADD,
+ EDG_WLL_NOTIF_REMOVE
+/* if adding new attribute, add conversion string to common/xml_conversions.c too !! */
+} edg_wll_NotifChangeOp;
+
+/** Modify the query conditions for this notification.
+ *
+ * If op is either EDG_WLL_NOTIF_ADD or EDG_WLL_NOTIF_REMOVE, for the sake
+ * of uniqueness the original conditions must have contained only a single
+ * OR-ed row of conditions on the attributes infolved in the change.
+ *
+ * \param op action to be taken on existing conditions,
+ * \see edg_wll_NotifChangeOp
+ */
+int edg_wll_NotifChange(
+ edg_wll_Context context,
+ const edg_wll_NotifId id,
+ edg_wll_QueryRec const * const * conditions,
+ edg_wll_NotifChangeOp op
+);
+
+/** Refresh the registration, i.e. extend its validity period.
+ * \param valid until when the registration is valid (NULL means no interest in
+ * the value
+ */
+
+int edg_wll_NotifRefresh(
+ edg_wll_Context context,
+ const edg_wll_NotifId id,
+ time_t *valid
+);
+
+/** Drop the registration.
+ * Server is instructed not to send notifications anymore, pending ones
+ * are discarded, listening socket is closed, and allocated memory freed.
+ */
+
+int edg_wll_NotifDrop(
+ edg_wll_Context context,
+ edg_wll_NotifId *id
+);
+
+/** Receive notification.
+ * The first incoming notification is returned.
+ * \param fd receive on this socket (-1 means the default for the context)
+ * \param timeout wait atmost this time long. (0,0) means polling, NULL waiting
+ * indefinitely
+ *
+ * \retval 0 notification received, state_out contains the current job state
+ * \retval EAGAIN no notification available, timeout occured
+ */
+
+int edg_wll_NotifReceive(
+ edg_wll_Context context,
+ int fd,
+ const struct timeval *timeout,
+ edg_wll_JobStat *state_out,
+ edg_wll_NotifId *id_out
+);
+
+
+/** Default socket descriptor where to select(2) for notifications.
+ * Even if nothing is available for reading freom the socket,
+ * there may be some data cached so calling \see edg_wll_NotifReceive
+ * may return notifications immediately.
+ *
+ * \retval >=0 socket descriptor
+ * \retval -1 error, details set in context
+ */
+
+int edg_wll_NotifGetFd(
+ edg_wll_Context context
+);
+
+/** Close the default local listening socket.
+ * Useful to force following \see edg_wll_NotifBind to open
+ * a new one.
+ */
+
+int edg_wll_NotifCloseFd(
+ edg_wll_Context context
+);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
--- /dev/null
+#ifndef __GLITE_LB_NOTIFID_H__
+#define __GLITE_LB_NOTIFID_H__
+typedef void *edg_wll_NotifId;
+#endif
--- /dev/null
+#ifndef __EDG_WORKLOAD_LOGGING_CLIENT_PRODUCER_H__
+#define __EDG_WORKLOAD_LOGGING_CLIENT_PRODUCER_H__
+
+/**
+ * \file edg/workload/logging/client/producer.h
+ * \brief client API for storing data into L&B service
+ */
+
+#ident "$Header$"
+/*
+@@@AUTO
+*/
+@@@LANG: C
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "glite/lb/context.h"
+#include "glite/lb/events.h"
+
+/* Event sources: */
+
+#if 0 /* obsolete */
+#define EDG_WLL_SOURCE_UI "UserInterface"
+#define EDG_WLL_SOURCE_RB "ResourceBroker"
+#define EDG_WLL_SOURCE_JSS "JobSubmissionService" /* aka Condor-G */
+#define EDG_WLL_SOURCE_JOBMGR "GlobusJobmanager"
+#define EDG_WLL_SOURCE_LRMS "LocalResourceManager"
+#define EDG_WLL_SOURCE_APP "Application"
+
+#define EDG_WLL_SOURCE_NS "NetworkServer"
+#define EDG_WLL_SOURCE_WM "WorkloadManager"
+#define EDG_WLL_SOURCE_BH "BigHelper"
+#define EDG_WLL_SOURCE_LM "LogMonitor"
+
+#endif
+
+/* Event formats: */
+
+#define EDG_WLL_FORMAT_COMMON "DATE=%s HOST=\"%|Us\" PROG=edg-wms LVL=%s DG.PRIORITY=%d DG.SOURCE=\"%|Us\" DG.SRC_INSTANCE=\"%|Us\" DG.EVNT=\"%s\" DG.JOBID=\"%s\" DG.SEQCODE=\"%|Us\" "
+#define EDG_WLL_FORMAT_USER "DG.USER=\"%|Us\" "
+@@@{
+# FIXME:
+# this is all functional, but doesn't fit to all common fields (eg. USER)
+#
+#gen "#define EDG_WLL_FORMAT_COMMON\t\"";
+#selectType $event '_common_';
+#for ($event->getFieldsOrdered) {
+# my $f = selectField $event $_;
+# my $fn = getName $f 'ULM';
+# my $fnu = uc $fn;
+# if (hasAlias $f 'ULM') {
+# gen "$fnu=%s ";
+# } else {
+# gen "DG\.$fnu=";
+# gen $f->toFormatString;
+# gen " ";
+# }
+#}
+#gen "\"\n";
+#
+for my $t (sort { $event->{order}->{$a} <=> $event->{order}->{$b} }
+ $event->getTypes) {
+ my $tu = uc $t;
+ gen "#define EDG_WLL_FORMAT_$tu\t\"";
+ selectType $event $t;
+ for ($event->getFieldsOrdered) {
+ my $f = selectField $event $_;
+ my $fn = $f->{name};
+ my $fnu = uc $fn;
+ gen "DG.$tu.$fnu=\\\"";
+ if ($f->{codes}) {
+ gen "%s";
+ } else {
+ gen $f->toFormatString;
+ }
+ gen "\\\" ";
+ }
+ gen "\"\n";
+}
+@@@}
+#define EDG_WLL_FORMAT_NOTIFICATION_COMMON "DATE=%s HOST=\"%|Us\" PROG=edg-wms LVL=%s DG.SOURCE=\"%|Us\" DG.SRC_INSTANCE=\"%|Us\" DG.TYPE=\"notification\" "
+#define EDG_WLL_FORMAT_SYSCMPSTAT "DG.SCHED.STATUS=\"%|Us\" "
+#define EDG_WLL_FORMAT_SYSCLSTAT "DG.SCHED.NODE=\"%|Us\" DG.SCHED.STATUS=\"%|Us\" "
+
+
+/* edg_wll_LogEvent shortcuts */
+@@@{
+for my $t (sort { $event->{order}->{$a} <=> $event->{order}->{$b} }
+ $event->getTypes) {
+ my $tu = uc $t;
+ my $a = "(edg_wll_Context context";
+ my $b = "(context,EDG_WLL_EVENT_$tu,EDG_WLL_FORMAT_$tu";
+ my $doc = qq{
+ * \\param context\tcontext to work with,
+};
+ selectType $event $t;
+ for ($event->getFieldsOrdered) {
+ my $f = selectField $event $_;
+ my $fn = $f->getName;
+ my $ft;
+ if ($f->{codes}) {
+# $ft = "enum edg_wll\_$t" . ucfirst $fn;
+ $ft = "char *";
+ } else {
+ $ft = $f->getType;
+ }
+ $ft = "const ".$ft;
+ my $fc = $f->getComment;
+ $a = $a . ", $ft $fn";
+ $b = $b . ", $fn";
+ $doc = $doc . " * \\param $fn\t$fc\n";
+ }
+ $a = $a . ")";
+ $b = $b . ")";
+ gen qq{
+/**
+ * \\fn int edg_wll_Log$t$a;
+ * \\brief simple wrapper around edg_wll_LogEvent for event $t} . $doc . qq{ * \\see edg_wll_LogEvent\(\)
+ */
+};
+ gen "\nextern int edg_wll_Log$t$a;\n\n";
+# gen qq{
+#int edg_wll_Log$t$a
+#\{
+# return edg_wll_LogEvent$b;
+#\}\n
+#};
+ for ($event->getFieldsOrdered) {
+ my $f = selectField $event $_;
+ my $fn = $f->getName;
+ my $ft;
+ if ($f->{codes}) {
+# $ft = "enum edg_wll\_$t" . ucfirst $fn;
+ $ft = "char *";
+ } else {
+ $ft = $f->getType;
+ }
+ my $ftreg = $ft;
+ $ftreg =~ s/\*/\\\*/g;
+ $ftreg = "const ".$ftreg;
+ my $fc = $f->getComment;
+ if ($f->{codes}) {
+ for (@{$f->{codes}}) {
+ my $code = uc $_->{name};
+ my $c = $a;
+ my $d = $b;
+ my $e = $doc;
+ $c =~ s/, $ftreg $fn//g;
+ $d =~ s/$fn/"$code"/g;
+ $e =~ s/ \* \\param $fn\t$fc\n//g;
+ gen qq{
+/**
+ * \\fn int edg_wll_Log$t$code$c;
+ * \\brief simple wrapper around edg_wll_LogEvent for event $t, $fn $code} . $e . qq{ * \\see edg_wll_LogEvent\(\)
+ */
+};
+ gen "\nextern int edg_wll_Log$t$code$c;\n\n";
+# gen qq{
+#int edg_wll_Log$t$code$c
+#\{
+# return edg_wll_LogEvent$d;
+#\}\n
+#};
+ }
+ }
+ }
+}
+@@@}
+
+
+/**
+ * Formats a logging message and sends it asynchronously to local-logger
+ * \brief generic asynchronous logging function
+ * \param context INOUT context to work with,
+ * \param event IN type of the event,
+ * \param fmt IN printf()-like format string,
+ * \param ... IN event specific values/data according to fmt,
+ * \retval 0 successful completition,
+ * \retval EINVAL bad jobId, unknown event code, or the format string together with the remaining arguments does not form a valid event,
+ * \retval ENOSPC L&B infrastructure failed to accept the event due to lack of disk space etc.,
+ * \retval ENOMEM failed to allocate memory,
+ * \retval ECONNREFUSED cannot connect to the specified local logger,
+ * \retval EAGAIN non blocking return from the call, the event may or may not get logged,
+ * \retval EDG_WLL_ERROR_NOJOBID logging call attempted without assigning jobId to the context.
+ */
+extern int edg_wll_LogEvent(
+ edg_wll_Context context,
+ edg_wll_EventCode event,
+ char *fmt, ...);
+
+
+/**
+ * Formats a logging message and sends it synchronously to local-logger
+ * \brief generic synchronous logging function
+ * \param context INOUT context to work with,
+ * \param event IN type of the event,
+ * \param fmt IN printf()-like format string,
+ * \param ... IN event specific values/data according to fmt,
+ * \retval 0 successful completition,
+ * \retval EINVAL bad jobId, unknown event code, or the format string together with the remaining arguments does not form a valid event,
+ * \retval ENOSPC L&B infrastructure failed to accept the event due to lack of disk space etc.,
+ * \retval ENOMEM failed to allocate memory,
+ * \retval ECONNREFUSED cannot connect to the specified local logger,
+ * \retval EAGAIN non blocking return from the call, the event may or may not get logged,
+ * \retval EDG_WLL_ERROR_NOJOBID logging call attempted without assigning jobId to the context,
+ * \retval EPERM the user is not authorized to add events to this job,
+ * \retval EDG_WLL_ERROR_DB_DUP_KEY exactly the same event has been already stored.
+ */
+extern int edg_wll_LogEventSync(
+ edg_wll_Context context,
+ edg_wll_EventCode event,
+ char *fmt, ...);
+
+
+/**
+ * Instructs interlogger to to deliver all pending events related to current job
+ * \brief flush events from interlogger
+ * \note sort of status query more than a command
+ * \param context INOUT context to work with,
+ * \param timeout INOUT wait at most this much time for completition, remaining time on return,
+ * \retval 0 successful completition,
+ * \retval EDG_WLL_ERROR_INTERLOG_TIMEOUT the inter-logger did not respond within the timeout,
+ * \retval EDG_WLL_ERROR_INTERLOG_CONLOST inter-logger lost connection to one or more servers,
+ * \retval EDG_WLL_ERROR_INTERLOG_AGAIN not all pending events were delivered within the timeout.
+ */
+extern int edg_wll_LogFlush(
+ edg_wll_Context context,
+ struct timeval *timeout);
+
+
+/**
+ * Instructs interlogger to to deliver all pending events
+ * \brief flush all events from interlogger
+ * \note same as edg_wll_LogFlush() for all jobs known to interlogger
+ * \see edg_wll_LogFlush()
+ */
+extern int edg_wll_LogFlushAll(
+ edg_wll_Context context,
+ struct timeval *timeout);
+
+/**
+ * Set a current job for given context.
+ * \note Should be called before any logging call.
+ * \param context INOUT context to work with
+ * \param job IN further logging calls are related to this job
+ * \param code IN sequence code as obtained from previous component
+ * \param flags IN flags on code handling (\see API documentation)
+ */
+extern int edg_wll_SetLoggingJob(
+ edg_wll_Context context,
+ const edg_wlc_JobId job,
+ const char * code,
+ int flags
+);
+
+
+/**
+ * Register job with L&B service.
+ * Done via logging REGJOB event, may generate subjob id's and create
+ * the parent-children associations.
+ * Set the job as current for the context and initialize sequence code.
+ *
+ * Partitionable jobs should set num_subjobs=0 initially,
+ * and re-register when number of subjobs becomes known.
+ *
+ * \param type EDG_WLL_JOB_SIMPLE, EDG_WLL_JOB_DAG, or EDG_WLL_JOB_PARTITIONABLE
+ * \param jdl user-specified JDL
+ * \param ns network server contact
+ * \param num_subjobs number of subjobs to create
+ * \param seed seed used for subjob id's generator.
+ * Use non-NULL value to be able to regenerate the set of jobid's
+ * \param subjobs returned subjob id's
+ */
+
+/* backward compatibility */
+#define EDG_WLL_JOB_SIMPLE EDG_WLL_REGJOB_SIMPLE
+
+extern int edg_wll_RegisterJob(
+ edg_wll_Context context,
+ const edg_wlc_JobId job,
+ enum edg_wll_RegJobJobtype type,
+ const char * jdl,
+ const char * ns,
+ int num_subjobs,
+ const char * seed,
+ edg_wlc_JobId ** subjobs
+);
+
+/**
+ * Synchronous variant of edg_wll_RegisterJob
+ */
+
+extern int edg_wll_RegisterJobSync(
+ edg_wll_Context context,
+ const edg_wlc_JobId job,
+ enum edg_wll_RegJobJobtype type,
+ const char * jdl,
+ const char * ns,
+ int num_subjobs,
+ const char * seed,
+ edg_wlc_JobId ** subjobs
+);
+
+/**
+ * Register subjobs in a batch.
+ * Mainly used to provide JDL's of individual subjobs in a more efficient
+ * way than logging them one by one.
+ * \param jdls array of JDL's
+ * \param subjobs array of jobid's in the same order
+ */
+
+extern int edg_wll_RegisterSubjobs(
+ edg_wll_Context context,
+ const edg_wlc_JobId parent,
+ char const * const * jdls,
+ const char * ns,
+ edg_wlc_JobId const * subjobs
+);
+
+
+/**
+ * Generate or regenerate set of subjob ID's.
+ * Calls the same algorithm used to generate subjob ID's in edg_wll_RegisterJob().
+ * Local semantics only, server is not contacted.
+ */
+
+extern int edg_wll_GenerateSubjobIds(
+ edg_wll_Context context,
+ const edg_wlc_JobId parent,
+ int num_subjobs,
+ const char * seed,
+ edg_wlc_JobId ** subjobs
+);
+
+
+enum edg_wll_Permission {
+ EDG_WLL_PERM_READ = 1,
+ EDG_WLL_PERM_WRITE = 4,
+ EDG_WLL_PERM_ADMIN = 8,
+};
+
+enum edg_wll_PermissionType {
+ EDG_WLL_PERM_ALLOW,
+ EDG_WLL_PERM_DENY,
+};
+
+enum edg_wll_ACLOperation {
+ EDG_WLL_ACL_ADD,
+ EDG_WLL_ACL_REMOVE,
+};
+
+enum edg_wll_UserIdType {
+ EDG_WLL_USER_SUBJECT, /* X.509 subject name */
+ EDG_WLL_USER_VOMS_GROUP, /* VOMS group membership */
+};
+
+/**
+ * Change ACL for given job.
+ * \param specification of user's credential
+ * \param user_id_type type of user_id,
+ * for EDG_WLL_USER_SUBJECT the user_id parameter is expected to be user's subject name
+ * for EDG_WLL_USER_VOMS_GROUP the user_id is expected to be of the form VO:group specifying required group membersip as managed by VOMS
+ * \param permission ACL permission to change
+ * \param permission_type type of given permission (allow or deny operation)
+ * \param operation operation to perform with ACL (add or remove record)
+ */
+
+extern int edg_wll_ChangeACL(
+ edg_wll_Context context,
+ const edg_wlc_JobId job,
+ const char * user_id,
+ enum edg_wll_UserIdType user_id_type,
+ enum edg_wll_Permission permission,
+ enum edg_wll_PermissionType permission_type,
+ enum edg_wll_ACLOperation operation
+);
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __EDG_WORKLOAD_LOGGING_CLIENT_PRODUCER_H__ */
--- /dev/null
+#ifndef __EDG_WORKLOAD_LOGGING_CLIENT_PURGE_H__
+#define __EDG_WORKLOAD_LOGGING_CLIENT_PURGE_H__
+
+#ident "$Header$"
+
+/** Purge or dump request */
+typedef struct _edg_wll_PurgeRequest {
+ char **jobs; /**< list of jobid's to work on */
+
+/** Purge jobs that are in the given states and "untouched" at least for the
+ * specified interval.
+ * Currently applicable for CLEARED, ABORTED, CANCELLED and OTHER (catchall).
+ * The other array members are for future extensions.
+ * Negative values stand for server defaults.
+ */
+ time_t timeout[EDG_WLL_NUMBER_OF_STATCODES];
+#define EDG_WLL_PURGE_JOBSTAT_OTHER EDG_WLL_JOB_UNDEF
+
+
+/**
+ * Actions to be taken and information required.
+ */
+ int flags;
+
+/** no dry run */
+#define EDG_WLL_PURGE_REALLY_PURGE 1
+/** return list of jobid matching the purge/dump criteria */
+#define EDG_WLL_PURGE_LIST_JOBS 2
+/** dump to a file on the sever */
+#define EDG_WLL_PURGE_SERVER_DUMP 4
+/** TODO: stream the dump info to the client */
+#define EDG_WLL_PURGE_CLIENT_DUMP 8
+/* ! when addning new constant, add it also to common/xml_conversions.c ! */
+
+
+/** private request processing data (for the reentrant functions) */
+/* TODO */
+
+} edg_wll_PurgeRequest;
+
+/** Output data of a purge or dump */
+typedef struct _edg_wll_PurgeResult {
+ char *server_file; /**< filename of the dump at the server */
+ char **jobs; /**< affected jobs */
+/* TODO: output of the streaming interface */
+} edg_wll_PurgeResult;
+
+
+/** Client side purge/dump
+ * \retval EAGAIN only partial result returned, call repeatedly to get all
+ * output data
+ */
+int edg_wll_Purge(
+ edg_wll_Context ctx,
+ edg_wll_PurgeRequest *request,
+ edg_wll_PurgeResult *result
+);
+
+#endif
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+
+<project name="LB Common component common properties">
+
+ <property file="build.properties" />
+ <property name="subsystem.name" value="${lb.subsystem.name}"/>
+ <property name="subsystem.prefix" value="${lb.subsystem.prefix}"/>
+ <property name="component.prefix" value="client-iface" />
+
+ <import file="${component.general.properties.file}" />
+
+</project>
--- /dev/null
+include Makefile.inc
+
+
+VPATH:=${src}
+AT3:=perl -I${lbconfig} ${lbproject}/at3
+
+SUFFIXES = .T
+
+DEBUG:=-g -O0
+CFLAGS:=${DEBUG} \
+ -I${stageinc} -I${src} -I${interface}\
+ -I${repository}/${globus}/include/${globusflavour} \
+ -I${repository}/${globus}/include/${globusflavour}/openssl \
+ -I${repository}/${expat}/include
+
+CXXFLAGS:=${CFLAGS}
+LDFLAGS:=-L${stagelib}
+
+COMPILE:=libtool --mode=compile ${CC} ${CFLAGS}
+LINK:=libtool --mode=link ${CC} ${LDFLAGS}
+INSTALL:=libtool --mode=install install
+
+GLOBUS_LIBS:= -L${repository}/${globus}/lib \
+ -lglobus_common_${globusflavour} \
+ -lssl_${globusflavour}
+
+EXT_LIBS:= ${GLOBUS_LIBS} \
+ -L${repository}/${ares}/lib -lares \
+ -L${repository}/${expat}/lib -lexpat \
+
+LIBOBJS:=connection.o consumer.o notification.o prod_proto.o \
+ producer.o uiwrap.o
+
+PLUSOBJS:=Event.o Job.o JobStatus.o Notification.o ServerConnection.o
+PUB_HDRS:=CountRef.h Event.h JobJobStatus.h Notification.h ServerConnection.h \
+ LoggingExceptions.h
+
+LIBLOBJS:=`echo ${LIBOBJS} | sed 's/\.o/\.lo/g'`
+PLUSLOBJS:=`echo ${PLUSOBJS} | sed 's/\.o/\.lo/g'`
+HELPERS:=-L${stagelib} -lglite_wms_tls_ssl_helpers
+
+LIB:=libglite_lb_client.la
+PLUSLIB:=libglite_lb_clientpp.la
+
+TOOLS:=dump load purge
+
+default: all
+
+compile: ${LIB} ${PLUSLIB} ${TOOLS} logevent
+
+check:
+ echo No unit tests so far.
+
+${LIB}: ${LIBOBJS}
+ ${LINK} -o $@ ${LIBLOBJS} -rpath ${stagelib} -lglite_lb_common ${HELPERS}
+# ${EXT_LIBS}
+
+${PLUSLIB}: ${PLUSOBJS}
+ ${LINK} -o $@ ${PLUSLOBJS} -rpath ${stagelib} ${LIB}
+
+stage export all: compile
+ ${INSTALL} -m 644 ${LIB} ${stagelib}
+ for p in ${TOOLS} logevent; do \
+ ${INSTALL} -m 755 "$$p" "${stagebin}/glite-lb-$$p"; \
+ done
+
+logevent: logevent.o args.o
+ ${LINK} -o $@ logevent.o args.o ${LIB} ${EXT_LIBS}
+
+${TOOLS}: %: %.o
+ ${LINK} -o $@ $< ${LIB} ${EXT_LIBS}
+
+${TOOLS}: ${LIB}
+
+${LIBOBJS}: %.o: %.c
+ ${COMPILE} -c $<
+
+%.o: %.c
+ ${CC} ${CFLAGS} -c $<
+
+%.c: %.c.T
+ rm -f $@
+ ${AT3} $< >$@ || rm -f $@
+ chmod -w $@ >/dev/null
+
+%.cpp: %.cpp.T
+ rm -f $@
+ ${AT3} $< >$@ || rm -f $@
+ chmod -w $@ >/dev/null
+
+
--- /dev/null
+<?xml version="1.0" encoding="UTF-8" ?>
+
+<project name="lb" default="dist">
+
+ <import file="../org.glite/project/baseline.properties.xml" />
+ <import file="./project/properties.xml"/>
+ <import file="${subsystem.properties.file}"/>
+ <import file="${global.properties.file}" />
+
+ <property file="${user.dependencies.file}"/>
+ <property file="${component.dependencies.file}" />
+ <property file="${subsystem.dependencies.file}" />
+ <property file="${global.dependencies.file}"/>
+
+ <import file="${subsystem.taskdefs.file}" />
+ <import file="${global.taskdefs.file}" />
+
+ <import file="${global.targets-external-dependencies.file}"/>
+ <import file="${global.targets-make.file}" />
+
+ <property file="${module.version.file}"/>
+
+ <target name="localinit"
+ description="Module specific initialization tasks">
+ <antcall target="lbmakefiles"/>
+ </target>
+
+ <target name="localcompile"
+ description="Module specific compile tasks">
+ </target>
+
+ <target name="localclean"
+ description="Module specific cleaning tasks">
+ </target>
+
+</project>
--- /dev/null
+#ifndef __EDG_WORKLOAD_LOGGING_CLIENT_COUNTREF_HPP__
+#define __EDG_WORKLOAD_LOGGING_CLIENT_COUNTREF_HPP__
+
+#define EWL_BEGIN_NAMESPACE namespace edg { namespace workload { namespace logging { namespace client {
+#define EWL_END_NAMESPACE } } } }
+
+EWL_BEGIN_NAMESPACE;
+
+template<typename T>
+class CountRef {
+public:
+ CountRef(void *);
+// CountRef(void *,void (*)(void *));
+
+ void use(void);
+ void release(void);
+
+ void *ptr;
+private:
+ int count;
+// void (*destroy)(void *);
+};
+
+template <typename T>
+CountRef<T>::CountRef(void *p)
+{
+ ptr = p;
+ count = 1;
+}
+
+template <typename T>
+void CountRef<T>::release(void)
+{
+ if (--count == 0) {
+ T::destroyFlesh(ptr);
+ delete this;
+ }
+}
+
+template <typename T>
+void CountRef<T>::use(void)
+{
+ count++;
+}
+
+EWL_END_NAMESPACE;
+
+#endif
--- /dev/null
+#ifndef __EDG_WORKLOAD_LOGGING_CLIENT_EVENT_HPP__
+#define __EDG_WORKLOAD_LOGGING_CLIENT_EVENT_HPP__
+
+#include "edg/workload/logging/client/CountRef.h"
+#include "edg/workload/common/jobid/JobId.h"
+
+#include <utility>
+#include <vector>
+#include <string>
+
+#ident "$Header$"
+
+/** @file Event.h
+ * @version $Revision$
+ */
+
+/*
+@@@AUTO
+*/
+@@@LANG: C++
+
+#include "edg/workload/logging/client/events.h"
+#include "edg/workload/logging/common/notifid.h"
+
+EWL_BEGIN_NAMESPACE;
+
+class Event {
+ friend class Job;
+ friend class ServerConnection;
+ friend class CountRef<Event>;
+public:
+ /** Event type codes.
+ * Identify which of the event fields are valid.
+ */
+
+ enum Type {
+ UNDEF = 0,
+@@@{
+ for my $e ($event->getTypesOrdered) {
+ my $u = uc $e;
+ my $c = getTypeComment $event $e;
+ gen "\t\t$u,\t/**< $c */\n";
+ }
+@@@}
+ TYPE_MAX
+ };
+
+ /** Event attribute symbolic identifier. */
+ enum Attr {
+@@@{
+ for (sort {$a cmp $b} getAllFields $event) {
+ my $u = $_;
+# $u =~ s/([a-z])([A-Z])/$1_$2/g;
+ $u = uc $u;
+
+ my $c = "\t/**\n";
+ for my $t (sort $event->getFieldOccurence($_)) {
+ selectType $event $t;
+ my $cc = getFieldComment $event $_;
+ $t = 'common' if $t eq '_common_';
+ $c .= "\t * $t: $cc\n";
+ }
+ $c .= "\t */\n";
+
+ gen "$c\t\t$u,\n";
+ }
+@@@}
+ ATTR_MAX
+ };
+
+@@@{
+ for my $f (getAllFields $event) {
+ for my $t (getFieldOccurence $event $f) {
+ my $ff;
+ my $ut;
+ my $utf;
+ if ($t eq '_common_') {
+ $ff = $f;
+ $ut = '';
+ $utf = '';
+ }
+ else {
+ selectType $event $t;
+ selectField $event $f;
+ $ff = getField $event;
+ $ut = uc $t . '_';
+ $utf = ucfirst $t;
+ }
+ if ($ff->{codes}) {
+ gen qq{
+! enum ${utf}Code \{
+};
+ for (@{$ff->{codes}}) {
+ gen qq{
+! $ut$_->{name}, /**< $_->{comment} */
+};
+ }
+ gen qq{
+! \};
+};
+ }
+ }
+ }
+@@@}
+
+ enum AttrType { INT_T, STRING_T, TIMEVAL_T, PORT_T, LOGSRC_T, JOBID_T, NOTIFID_T };
+
+ Type type;
+
+ Event(void);
+ Event(edg_wll_Event *);
+ Event(const Event &);
+ ~Event(void);
+
+
+ /** Assign new Event to an existing instance. */
+ Event & operator= (const Event &);
+
+ /** String representation of the event type */
+ const std::string & name(void) const;
+
+ /** Retrieve integer attribute */
+ int getValInt(Attr) const;
+
+ /** Retrieve string attribute */
+ std::string getValString(Attr) const;
+
+ /** Retrieve time attribute */
+ struct timeval getValTime(Attr) const;
+
+ /** Retrieve jobid attribute */
+ const edg::workload::common::jobid::JobId getValJobId(Attr) const;
+
+ /** Attribute name */
+ const std::string & getAttrName(Attr) const;
+
+ /** List of attributes and types valid for this instance */
+ const std::vector<std::pair<Attr,AttrType> > & getAttrs(void) const;
+
+private:
+ static void destroyFlesh(void *);
+ CountRef<Event> *flesh;
+};
+
+EWL_END_NAMESPACE;
+
+#endif
--- /dev/null
+#ifndef __EDG_WORKLOAD_LOGGING_CLIENT_JOB_HPP__
+#define __EDG_WORKLOAD_LOGGING_CLIENT_JOB_HPP__
+
+#ident "$Header$"
+
+#include "edg/workload/common/jobid/JobId.h"
+#include "edg/workload/logging/client/Event.h"
+#include "edg/workload/logging/client/JobStatus.h"
+#include "edg/workload/logging/client/ServerConnection.h"
+
+
+/**
+ * @file Job.h
+ * @version $Revision$
+ */
+
+EWL_BEGIN_NAMESPACE;
+
+/** L&B job.
+ * Implementation of L&B job-specific calls.
+ * Connection to the server is maintained transparently.
+*/
+
+class Job {
+public:
+ Job(void);
+ Job(const edg::workload::common::jobid::JobId &);
+ ~Job();
+
+ /** Assign new JobId to an existing instance.
+ * Connection to server is preserved if possible.
+ */
+
+ Job & operator= (const edg::workload::common::jobid::JobId &);
+
+/**
+ * Status retrieval bitmasks. Used ORed as Job::status() argument,
+ * determine which status fields are actually retrieved.
+ */
+ static const int STAT_CLASSADS; /**< various job description fields */
+ static const int STAT_CHILDREN; /**< list of subjob JobId's */
+ static const int STAT_CHILDSTAT; /**< apply the flags recursively to subjobs */
+
+ /** Return job status */
+ JobStatus status(int) const;
+
+ /** Return all events corresponding to this job */
+ void log(std::vector<Event> &) const;
+ const std::vector<Event> log(void) const;
+
+ /** Return last known address of a listener associated to the job.
+ * \param name name of the listener
+ * \return hostname and port number
+ */
+ const std::pair<std::string,uint16_t> queryListener(const std::string & name) const;
+
+ /** Manipulate LB parameters, the same as for edg_wll_Context in C */
+ void setParam(edg_wll_ContextParam, int);
+ void setParam(edg_wll_ContextParam, const std::string);
+ void setParam(edg_wll_ContextParam, const struct timeval &);
+
+ int getParamInt(edg_wll_ContextParam) const;
+ std::string getParamString(edg_wll_ContextParam) const;
+ struct timeval getParamTime(edg_wll_ContextParam) const;
+
+private:
+ ServerConnection server;
+ edg::workload::common::jobid::JobId jobId;
+};
+
+EWL_END_NAMESPACE;
+
+#endif
--- /dev/null
+#ifndef __EDG_WORKLOAD_LOGGING_CLIENT_JOBSTATUS_HPP__
+#define __EDG_WORKLOAD_LOGGING_CLIENT_JOBSTATUS_HPP__
+
+/*
+@@@AUTO
+*/
+
+@@@LANG: C++
+
+#include "edg/workload/logging/client/CountRef.h"
+#include "edg/workload/common/jobid/JobId.h"
+
+#include "edg/workload/common/jobid/jobid.h"
+#include <sys/time.h>
+#include "edg/workload/logging/client/jobstat.h"
+
+#include <string>
+#include <utility>
+#include <vector>
+
+EWL_BEGIN_NAMESPACE;
+
+/**
+ * Description of job status.
+ * The status is computed from a sequence of logged events
+ */
+
+
+class JobStatus {
+ friend class Job;
+ friend class CountRef<JobStatus>;
+public:
+ enum Code {
+ UNDEF = 0, /**< indicates invalid, i.e. uninitialized instance */
+@@@{
+ for my $stat ($status->getTypesOrdered)
+ {
+ my $u = uc($stat);
+ my $c = getTypeComment $status $stat;
+ gen qq{
+! $u, /**< $c */
+};
+ }
+@@@}
+ CODE_MAX
+ };
+
+ enum Attr {
+@@@{
+ selectType $status '_common_';
+ for my $u (sort {$a cmp $b} getAllFields $status) {
+ selectField $status $u;
+ my $f = getField $status;
+ $u =~ s/([a-z])([A-Z])/$1_$2/g;
+ $u = uc $u;
+
+ gen "\t/** $f->{comment} */\n\t\t$u,\n";
+ }
+@@@}
+ ATTR_MAX
+ };
+
+@@@{
+ selectType $status '_common_';
+ for my $n (getAllFields $status) {
+ selectField $status $n;
+ my $f = getField $status;
+ if ($f->{codes}) {
+ my $n = uc getName $f;
+ gen qq{
+! enum \{
+};
+ for (@{$f->{codes}}) {
+ gen qq{
+! $n\_$_->{name}, /**< $_->{comment} */
+};
+ }
+ gen qq{
+! \};
+};
+ }
+ }
+@@@}
+ enum AttrType { INT_T,
+ STRING_T,
+ TIMEVAL_T,
+ BOOL_T,
+ JOBID_T,
+ INTLIST_T,
+ STRLIST_T,
+ TAGLIST_T,
+ STSLIST_T
+ };
+
+ /** Numeric status code */
+ Code status;
+
+ /** String representation of the status code */
+ const std::string & name(void) const;
+
+ /** Retrieve integer attribute */
+ int getValInt(Attr) const;
+
+ /** Retrieve string attribute */
+ std::string getValString(Attr) const;
+
+ /** Retrieve time attribute */
+ struct timeval getValTime(Attr) const;
+
+ /** Retrieve jobid attribute */
+ const edg::workload::common::jobid::JobId getValJobId(Attr) const;
+
+ /** Retrieve bool attribute */
+ bool getValBool(Attr) const;
+
+ /** Retrieve int list attribute */
+ const std::vector<int> getValIntList(Attr) const;
+
+ /** Retrieve string list attribute */
+ const std::vector<std::string> getValStringList(Attr) const;
+
+ /** Retrieve tag list attribute */
+ const std::vector<std::pair<std::string,std::string> > getValTagList(Attr) const;
+
+ /** Retrieve job status list attribute */
+ const std::vector<JobStatus> getValJobStatusList(Attr) const;
+
+ /** Attribute name */
+ const std::string& getAttrName(Attr) const;
+
+ /** List of attributes and types valid for this instance */
+ const std::vector<std::pair<Attr,AttrType> >& getAttrs(void) const;
+
+ JobStatus(void);
+ JobStatus(const JobStatus &);
+ JobStatus & operator=(const JobStatus &);
+ JobStatus(const edg_wll_JobStat &);
+ JobStatus & operator=(const edg_wll_JobStat&);
+ virtual ~JobStatus();
+
+protected:
+ edg_wll_JobStat *c_ptr(void);
+
+private:
+ static void destroyFlesh(void *);
+ CountRef<JobStatus> *flesh;
+};
+
+EWL_END_NAMESPACE;
+
+#endif
+
--- /dev/null
+#ifndef __EDG_WORKLOAD_LOGGING_CLIENT_LOGGING_EXCEPTIONS_HPP__
+#define __EDG_WORKLOAD_LOGGING_CLIENT_LOGGING_EXCEPTIONS_HPP__
+
+#include "edg/workload/common/utilities/Exceptions.h"
+
+#include <pthread.h>
+
+#ident "$Header$"
+
+/** @file LoggingExceptions.h
+ * @version $Revision$
+ */
+
+EWL_BEGIN_NAMESPACE;
+
+class Exception: public edg::workload::common::utilities::Exception {
+public:
+
+ /* constructor for mandatory fields */
+ Exception(const std::string& source,
+ int line_number,
+ const std::string& method,
+ int code,
+ const std::string& exception)
+ : edg::workload::common::utilities::Exception(source,
+ line_number,
+ method,
+ code,
+ "edg::workload::logging::Exception")
+ { error_message = exception; };
+
+ /* constructor for mandatory fields AND exception chain */
+ Exception(const std::string& source,
+ int line_number,
+ const std::string& method,
+ int code,
+ const std::string& exception,
+ const edg::workload::common::utilities::Exception &exc)
+ : edg::workload::common::utilities::Exception(source,
+ line_number,
+ method,
+ code,
+ "edg::workload::logging::Exception")
+ { error_message = exception + ": " + exc.what(); };
+};
+
+
+class LoggingException: public Exception {
+public:
+
+ /* constructor for mandatory fields */
+ LoggingException(const std::string& source,
+ int line_number,
+ const std::string& method,
+ int code,
+ const std::string& exception)
+ : Exception(source, line_number, method, code, exception)
+ {};
+
+ /* constructor for mandatory fields AND exception chain */
+ LoggingException(const std::string& source,
+ int line_number,
+ const std::string& method,
+ int code,
+ const std::string& exception,
+ const edg::workload::common::utilities::Exception &exc)
+ : Exception(source, line_number, method, code, exception)
+ {};
+};
+
+
+class OSException: public Exception {
+public:
+
+ /* constructor for mandatory fields */
+ OSException(const std::string& source,
+ int line_number,
+ const std::string& method,
+ int code,
+ const std::string& exception)
+ : Exception(source,
+ line_number,
+ method,
+ code,
+ exception + ": " + strerror(code))
+ {};
+
+ /* constructor for mandatory fields AND exception chain */
+ OSException(const std::string& source,
+ int line_number,
+ const std::string& method,
+ int code,
+ const std::string& exception,
+ const edg::workload::common::utilities::Exception &exc)
+ : Exception(source,
+ line_number,
+ method,
+ code,
+ exception + ": " + strerror(code))
+ {};
+};
+
+
+#define EXCEPTION_MANDATORY \
+ __FILE__, \
+ __LINE__, \
+ std::string(CLASS_PREFIX) + __FUNCTION__
+
+#define STACK_ADD
+
+/* note: we can use __LINE__ several times in macro, it is expanded into one row */
+#define throw_exception(context, exception) \
+{ STACK_ADD; \
+ { \
+ char *text, *desc; \
+ int code; \
+ std::string exc; \
+ \
+ code = edg_wll_Error((context), &text, &desc); \
+ exc = exception; \
+ if (text) { \
+ exc += ": "; \
+ exc += text; \
+ } \
+ if (desc) { \
+ exc += ": "; \
+ exc += desc; \
+ } \
+ free(text); \
+ free(desc); \
+ throw LoggingException(EXCEPTION_MANDATORY, \
+ code, \
+ exc); \
+ } \
+}
+
+#define check_result(code, context, desc) \
+ if((code)) throw_exception((context), desc)
+
+
+
+EWL_END_NAMESPACE;
+
+#endif
--- /dev/null
+#ifndef __EDG_WORKLOAD_LOGGING_CLIENT_NOTIFICATION_HPP__
+#define __EDG_WORKLOAD_LOGGING_CLIENT_NOTIFICATION_HPP__
+
+#include "edg/workload/logging/client/consumer.h"
+#include "edg/workload/logging/client/notification.h"
+
+#include "edg/workload/common/jobid/JobId.h"
+#include "edg/workload/logging/client/JobStatus.h"
+
+
+EWL_BEGIN_NAMESPACE;
+
+
+/** Manage LB notifications.
+ * Simplified API, covers only a subset of C API functinality
+ */
+
+class Notification {
+public:
+ Notification();
+
+ /** Create from NotifId */
+ Notification(const std::string);
+
+ /** Create from server,port pair */
+ Notification(const std::string,const u_int16_t);
+
+ ~Notification();
+
+ std::string getNotifId() const; /**< retrieve NotifId */
+ time_t getValid() const; /**< until when it is valid */
+ int getFd() const; /**< local listener filedescriptor */
+
+ /** Add this job to the list.
+ * Local operation only, Register() has to be called
+ * to propagate changes to server
+ */
+ void addJob(const edg::workload::common::jobid::JobId &);
+
+ /** Remove job from the list, local op again. */
+ void removeJob(const edg::workload::common::jobid::JobId &);
+
+ /** Get jobs on the list */
+ std::string getJobs();
+
+ /** Receive notifications on these states */
+ void setStates(const std::vector<edg::workload::logging::client::JobStatus::Code> &);
+
+ /** Get states */
+ std::string getStates();
+
+ /** Register (or re-register, i.e. change and extend)
+ * with the server
+ */
+ void Register();
+
+ /** Receive notification.
+ * Blocks at most the specified timeout (maybe 0 for local polling).
+ * \retval 0 OK
+ * \retval 1 timeout
+ */
+ int receive(edg::workload::logging::client::JobStatus &,timeval &);
+
+private:
+ std::vector<edg::workload::common::jobid::JobId> jobs;
+ std::vector<edg::workload::logging::client::JobStatus::Code> states;
+
+ edg_wll_Context ctx;
+ edg_wll_NotifId notifId;
+ time_t valid;
+};
+
+
+EWL_END_NAMESPACE;
+
+#endif
--- /dev/null
+#ifndef __EDG_WORKLOAD_LOGGING_CLIENT_SERVERCONNECTION_HPP__
+#define __EDG_WORKLOAD_LOGGING_CLIENT_SERVERCONNECTION_HPP__
+
+#ident "$Header$"
+
+/**
+ * @file ServerConnection.h
+ * @version $Revision$
+ */
+
+#include <string.h>
+#include <list>
+
+#include "edg/workload/common/jobid/JobId.h"
+#include "edg/workload/logging/client/Event.h"
+#include "edg/workload/logging/client/JobStatus.h"
+
+#include "edg/workload/logging/client/consumer.h"
+
+EWL_BEGIN_NAMESPACE;
+
+/** Auxiliary class to hold an atomic query condition. */
+class QueryRecord {
+public:
+ friend class ServerConnection;
+ friend edg_wll_QueryRec *convertQueryVector(const std::vector<QueryRecord> &in);
+
+ /* IMPORTANT: must match lbapi.h */
+ enum Attr {
+ UNDEF=0, /**< Not-defined value, used to terminate lists etc. */
+ JOBID, /**< Job Id \see _edg_wll_QueryRec */
+ OWNER, /**< Job owner \see _edg_wll_QueryRec */
+ STATUS, /**< Current job status */
+ LOCATION, /**< Where is the job processed */
+ DESTINATION, /**< Destination CE */
+ DONECODE, /**< Minor done status (OK,fail,cancel) */
+ USERTAG, /**< User tag (not implemented yet) */
+ TIME, /**< Timestamp \see _edg_wll_QueryRec */
+ LEVEL, /**< Logging level (see "dglog.h") * \see _edg_wll_QueryRec */
+ HOST, /**< Where the event was generated */
+ SOURCE, /**< Source component */
+ INSTANCE, /**< Instance of the source component */
+ EVENT_TYPE, /**< Event type \see _edg_wll_QueryRec */
+ CHKPT_TAG, /**< Checkpoint tag */
+ RESUBMITTED, /**< Job was resubmitted */
+ PARENT, /**< Job was resubmitted */
+ EXITCODE, /**< Unix exit code */
+ };
+
+ enum Op {
+ EQUAL=EDG_WLL_QUERY_OP_EQUAL,
+ LESS=EDG_WLL_QUERY_OP_LESS,
+ GREATER=EDG_WLL_QUERY_OP_GREATER,
+ WITHIN=EDG_WLL_QUERY_OP_WITHIN,
+ UNEQUAL=EDG_WLL_QUERY_OP_UNEQUAL
+ };
+
+ QueryRecord();
+
+ /* copy and assignment */
+ QueryRecord(const QueryRecord &);
+ QueryRecord& operator=(const QueryRecord &);
+
+ /* constructors for simple attribute queries */
+ QueryRecord(const Attr, const Op, const std::string &);
+ QueryRecord(const Attr, const Op, const int);
+ QueryRecord(const Attr, const Op, const struct timeval &);
+ QueryRecord(const Attr, const Op, const edg::workload::common::jobid::JobId&);
+ /* this one is for attr==TIME and particular state */
+ QueryRecord(const Attr, const Op, const int, const struct timeval &);
+
+ /* constructors for WITHIN operator */
+ QueryRecord(const Attr, const Op, const std::string &, const std::string &);
+ QueryRecord(const Attr, const Op, const int, const int);
+ QueryRecord(const Attr, const Op, const struct timeval &, const struct timeval &);
+ QueryRecord(const Attr, const Op, const int, const struct timeval &, const struct timeval &);
+
+ /* convenience for user tags */
+ QueryRecord(const std::string &, const Op, const std::string &);
+ QueryRecord(const std::string &, const Op, const std::string &, const std::string &);
+
+ ~QueryRecord();
+
+ static const std::string AttrName(const Attr) ;
+
+protected:
+
+ /* conversion to C API type */
+ operator edg_wll_QueryRec() const;
+
+private:
+ Attr attr;
+ Op oper;
+ std::string tag_name;
+ int state;
+ std::string string_value;
+ edg::workload::common::jobid::JobId jobid_value;
+ int int_value;
+ struct timeval timeval_value;
+ std::string string_value2;
+ int int_value2;
+ struct timeval timeval_value2;
+};
+
+
+/** Supported aggregate operations */
+enum AggOp { AGG_MIN=1, AGG_MAX, AGG_COUNT };
+
+
+/**
+ * Connection to the L&B server.
+ * Maintain connection to the server.
+ * Implement non job-specific API calls
+ */
+
+class ServerConnection {
+public:
+ friend class Job;
+
+ ServerConnection(void);
+
+ /* DEPRECATED: do not use
+ * connections are now handled automagically inside the implementation
+ */
+ ServerConnection(const std::string &);
+
+ /** Open connection to a given server */
+ void open(const std::string &);
+
+ /** Close the current connection */
+ void close(void);
+
+ /* END DEPRECATED */
+
+ /* set & get parameter methods */
+
+ /* consumer parameter settings */
+ void setQueryServer(const std::string&, int);
+ void setQueryTimeout(int);
+
+ void setX509Proxy(const std::string&);
+ void setX509Cert(const std::string&, const std::string&);
+
+ std::pair<std::string, int> getQueryServer() const;
+ int getQueryTimeout() const;
+
+ std::string getX509Proxy() const;
+ std::pair<std::string, std::string> getX509Cert() const;
+
+ /* end of set & get */
+
+ virtual ~ServerConnection();
+
+
+ /* consumer API */
+
+ /** Retrieve the set of single indexed attributes.
+ * outer vector elements correspond to indices
+ * inner vector elements correspond to index columns
+ * if .first of the pair is USERTAG, .second is its name
+ * if .first is TIME, .second is state name
+ * otherwise .second is meaningless (empty string anyway)
+ */
+ std::vector<std::vector<std::pair<QueryRecord::Attr,std::string> > >
+ getIndexedAttrs(void);
+
+ /** Retrieve hard and soft result set size limit */
+ std::pair<int,int> getLimits(void) const;
+
+ /** Set the soft result set size limit */
+ void setQueryJobsLimit(int);
+ void setQueryEventsLimit(int);
+
+ /** Retrieve all events satisfying the query records
+ * @param job_cond, event_cond - vectors of conditions to be satisfied
+ * by jobs as a whole or particular events, conditions are ANDed
+ * @param events vector of returned events
+ */
+ void queryEvents(const std::vector<QueryRecord>& job_cond,
+ const std::vector<QueryRecord>& event_cond,
+ std::vector<Event>&) const;
+
+ const std::vector<Event> queryEvents(const std::vector<QueryRecord>& job_cond,
+ const std::vector<QueryRecord>& event_cond) const;
+
+ const std::list<Event> queryEventsList(const std::vector<QueryRecord>& job_cond,
+ const std::vector<QueryRecord>& event_cond) const;
+
+
+ /** The same as queryEvents but return only an aggregate.
+ * @param job_cond, event_cond - vectors of conditions to be satisfied
+ * by jobs as a whole or particular events, conditions are ANDed
+ * @param op aggregate operator to apply
+ * @param attr attribute to apply the operation to
+ */
+ std::string queryEventsAggregate(const std::vector<QueryRecord>& job_cond,
+ const std::vector<QueryRecord>& event_cond,
+ enum AggOp const op,
+ std::string const attr) const;
+
+
+ /** Retrieve all events satisfying the query records
+ * @param job_cond, event_cond - vectors of vectors of job or event conditions,
+ * respectively. The inner vectors are logically ANDed, the outer are ORed
+ * (cond1 AND cond2 AND ...) OR (condN AND ...)
+ * @param events vector of returned events
+ */
+ void queryEvents(const std::vector<std::vector<QueryRecord> >& job_cond,
+ const std::vector<std::vector<QueryRecord> >& event_cond,
+ std::vector<Event>&) const;
+
+ const std::vector<Event>
+ queryEvents(const std::vector<std::vector<QueryRecord> >& job_cond,
+ const std::vector<std::vector<QueryRecord> >& event_cond) const;
+
+
+ /** Retrieve jobs satisfying the query records, including their states
+ * @param query vector of Query records that are anded to form the
+ * query
+ * @param ids vector of returned job id's
+ * @param states vector of returned job states
+ */
+
+ void queryJobs(const std::vector<QueryRecord>& query,
+ std::vector<edg::workload::common::jobid::JobId>& ids) const;
+
+ const std::vector<edg::workload::common::jobid::JobId>
+ queryJobs(const std::vector<QueryRecord>& query) const;
+
+
+ /** Retrieve jobs satisfying the query records, including their states
+ * @param query vector of Query record vectors that are ORed and ANDed to form the
+ * query
+ * @param ids vector of returned job id's
+ * @param states vector of returned job states
+ */
+
+ void queryJobs(const std::vector<std::vector<QueryRecord> >& query,
+ std::vector<edg::workload::common::jobid::JobId>& ids) const;
+
+ const std::vector<edg::workload::common::jobid::JobId>
+ queryJobs(const std::vector<std::vector<QueryRecord> >& query) const;
+
+ /** Retrieve jobs satisfying the query records, including status
+ * information
+ * @param query vector of Query records that are anded to form the
+ * query
+ * @param ids vector of returned job id's
+ * @param states vector of returned job states
+ */
+ void queryJobStates(const std::vector<QueryRecord>& query,
+ int flags,
+ std::vector<JobStatus> & states) const;
+ const std::vector<JobStatus> queryJobStates(const std::vector<QueryRecord>& query,
+ int flags) const;
+
+ const std::list<JobStatus> queryJobStatesList(const std::vector<QueryRecord>& query,
+ int flags) const;
+
+ /** Retrieve jobs satisfying the query records, including status
+ * information
+ * @param query vector of Query records that are anded to form the
+ * query
+ * @param ids vector of returned job id's
+ * @param states vector of returned job states
+ */
+ void queryJobStates(const std::vector<std::vector<QueryRecord> >& query,
+ int flags,
+ std::vector<JobStatus> & states) const;
+ const std::vector<JobStatus>
+ queryJobStates(const std::vector<std::vector<QueryRecord> >& query,
+ int flags) const;
+
+ /** States of all user's jobs.
+ * Convenience wrapper around queryJobs.
+ */
+ void userJobStates(std::vector<JobStatus>& stateList) const;
+ const std::vector<JobStatus> userJobStates() const;
+
+
+ /** JobId's of all user's jobs.
+ * Convenience wrapper around queryJobs.
+ */
+ void userJobs(std::vector<edg::workload::common::jobid::JobId> &) const;
+ const std::vector<edg::workload::common::jobid::JobId> userJobs() const;
+
+ /** Manipulate LB parameters, the same as for edg_wll_Context in C */
+ void setParam(edg_wll_ContextParam, int);
+ void setParam(edg_wll_ContextParam, const std::string);
+ void setParam(edg_wll_ContextParam, const struct timeval &);
+
+ int getParamInt(edg_wll_ContextParam) const;
+ std::string getParamString(edg_wll_ContextParam) const;
+ struct timeval getParamTime(edg_wll_ContextParam) const;
+
+protected:
+
+ edg_wll_Context getContext(void) const;
+
+private:
+ edg_wll_Context context;
+};
+
+EWL_END_NAMESPACE;
+
+#endif
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+
+<project name="LB client component common properties">
+
+ <property file="build.properties" />
+ <property name="subsystem.name" value="${lb.subsystem.name}"/>
+ <property name="subsystem.prefix" value="${lb.subsystem.prefix}"/>
+ <property name="component.prefix" value="client" />
+
+ <import file="${component.general.properties.file}" />
+
+</project>
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+
+<project name="LB Subsystem common tasks and types definitions">
+</project>
--- /dev/null
+/*
+@@@AUTO
+*/
+
+#include <utility>
+#include <vector>
+#include <string>
+#include <stdio.h>
+
+#include <errno.h>
+
+#include "glite/wms/jobid/cjobid.h"
+
+#include "Event.h"
+#include "glite/wms/jobid/JobIdExceptions.h"
+#include "LoggingExceptions.h"
+
+#include "glite/lb/consumer.h"
+#include "glite/lb/events.h"
+#include "glite/lb/notifid.h"
+
+EWL_BEGIN_NAMESPACE;
+
+#define CLASS_PREFIX "edg::workload::logging::Event::"
+
+@@@{
+sub typeswitch {
+ my $ftype = shift;
+ my $resc = shift;
+ local $_;
+ my %ctype;
+ $ctype{$_} = 1 while $_ = shift;
+
+ $resc = 'break;' unless $resc;
+
+ gen $indent."switch (attr) {\n";
+ selectType $event $ftype;
+ for (getFields $event) {
+ my $f = selectField $event $_;
+ if($ctype{$f->{type}}) {
+ my $cstr = $ftype eq '_common_' ? 'any' : lcfirst $ftype;
+ my $cname = getName $f 'C';
+ gen "$indent\tcase Event::".uc($f->{name}).": return(cev->$cstr.$cname);\n";
+ } elsif (($f->{type} eq "int") &&
+ ($ctype{"string"}) &&
+ $f->{codes}) {
+ # conversion from int to string (well, enum to string)
+ my $cstr = $ftype eq '_common_' ? 'any' : lcfirst $ftype;
+ my $cname = getName $f 'C';
+ my $fn = $ftype eq '_common_' ? "" : ucfirst $ftype;
+ my $c = $fn . ucfirst $f->{name};
+ $cast = ($c eq 'Level') ? "(edg_wll_Level)" : "";
+ gen "$indent\tcase Event::".uc($f->{name}).": return((const char *)edg_wll_${c}ToString(${cast}cev->$cstr.$cname));\n";
+ } elsif (($f->{type} eq "jobid") &&
+ ($ctype{"string"})) {
+ # conversion from jobid to string
+ }
+ }
+ gen "$indent\tdefault: $resc\n" if $resc;
+ gen "$indent\}\n";
+}
+@@@}
+
+Event::Event(void)
+{
+ type = UNDEF;
+ flesh = 0;
+}
+
+
+Event::Event(const Event &in)
+{
+ type = in.type;
+ flesh = in.flesh;
+ if (flesh) flesh->use();
+}
+
+
+Event::Event(edg_wll_Event *in)
+{
+ type = (Type)in->type;
+ flesh = new CountRef<Event>((void*)in);
+}
+
+
+Event::~Event(void)
+{
+ if (flesh) flesh->release();
+}
+
+
+Event &
+Event::operator= (const Event &in)
+{
+ if (flesh) flesh->release();
+ type = in.type;
+ flesh = in.flesh;
+ if (flesh) flesh->use();
+
+ return *this;
+}
+
+int Event::getValInt(Attr attr) const
+{
+ edg_wll_Event const *cev = (edg_wll_Event *) flesh->ptr;
+
+@@@{
+ $indent = "\t";
+ typeswitch '_common_',undef,'int','port','logsrc';
+@@@}
+
+ switch (cev->type) {
+@@@{
+ $indent = "\t\t";
+ for my $t (getTypes $event) {
+ gen "\t\tcase ".uc($t).":\n";
+ typeswitch $t,'goto badattr;','int','port','logsrc';
+ }
+@@@}
+ default:
+ STACK_ADD;
+ throw(Exception(EXCEPTION_MANDATORY, EINVAL,
+ "attribute is not of int type"));
+ }
+badattr:
+ STACK_ADD;
+ throw(Exception(EXCEPTION_MANDATORY, ENOENT, "invalid attribute"));
+ return -1; /* gcc, shut up! */
+}
+
+static char const *get_string_val(const edg_wll_Event *cev, Event::Attr attr)
+{
+@@@{
+ $indent = "\t";
+ typeswitch '_common_',undef,'string';
+@@@}
+
+ switch (cev->type) {
+@@@{
+ $indent = "\t\t";
+ for my $t (getTypes $event) {
+ gen "\t\tcase Event::".uc($t).":\n";
+ typeswitch $t,'goto badattr;','string';
+ }
+@@@}
+ default:
+ STACK_ADD;
+ throw(Exception(EXCEPTION_MANDATORY, EINVAL,
+ "attribute is not of string type and can not be converted"));
+ }
+badattr:
+ STACK_ADD;
+ throw(Exception(EXCEPTION_MANDATORY, ENOENT, "invalid attribute"));
+ return NULL; /* gcc, shut up! */
+}
+
+
+std::string
+Event::getValString(Attr attr) const
+{
+ edg_wll_Event const *cev = (edg_wll_Event *) flesh->ptr;
+ std::string ret;
+
+ try {
+ char const *s = get_string_val(cev,attr);
+ if (s) ret.assign(s);
+ return ret;
+ } catch (Exception &e) {
+ STACK_ADD;
+ throw;
+ }
+}
+
+
+struct timeval
+Event::getValTime(Attr attr) const
+{
+ edg_wll_Event const *cev = (edg_wll_Event *) flesh->ptr;
+@@@{
+ $indent = "\t";
+ typeswitch '_common_',undef,'timeval';
+@@@}
+
+ /* XXX
+ * to make things simpler we don't include this here as there are no
+ * type specific timeval attributes currently
+ *
+ * switch (cev->type) {
+ */
+
+ STACK_ADD;
+ throw(Exception(EXCEPTION_MANDATORY, ENOENT, "invalid attribute"));
+}
+
+static
+edg_wlc_JobId
+get_val_jobid(edg_wll_Event const *cev, Event::Attr attr)
+{
+@@@{
+ $indent = "\t";
+ typeswitch '_common_', undef,'jobid';
+@@@}
+ switch (cev->type) {
+@@@{
+ $indent = "\t\t";
+ for my $t (getTypes $event) {
+ gen "\t\tcase Event::".uc($t).":\n";
+ typeswitch $t,'goto badattr;','jobid';
+ }
+@@@}
+ default:
+ STACK_ADD;
+ throw(Exception(EXCEPTION_MANDATORY, EINVAL,
+ "attribute is not of jobid type"));
+ }
+badattr:
+ STACK_ADD;
+ throw(Exception(EXCEPTION_MANDATORY, ENOENT, "invalid attribute"));
+ return NULL; /* gcc, shut up! */
+}
+
+const
+edg::workload::common::jobid::JobId
+Event::getValJobId(Attr attr) const
+{
+ edg_wll_Event const *cev = (edg_wll_Event *) flesh->ptr;
+ try {
+ edg_wlc_JobId job_id = get_val_jobid(cev,attr);
+ return(edg::workload::common::jobid::JobId(job_id));
+ }
+ catch (Exception &e) {
+ STACK_ADD;
+ throw;
+ }
+
+}
+
+
+static std::string const names[Event::TYPE_MAX] = {
+ "undefined",
+@@@{
+ for (sort { $event->{order}->{$a} <=> $event->{order}->{$b} }
+ $event->getTypes)
+ {
+ gen "\t\"$_\",\n";
+ }
+@@@}
+};
+
+const std::string &
+Event::name(void) const
+{
+ if (type<0 || type>TYPE_MAX) {
+ STACK_ADD;
+ throw(Exception(EXCEPTION_MANDATORY, EINVAL, "invalid event type"));
+ }
+ return names[type];
+}
+
+
+static
+std::string const attr_names[Event::ATTR_MAX] = {
+@@@{
+ for (sort {$a cmp $b} getAllFields $event) {
+ gen "\t\"$_\",\n";
+ }
+@@@}
+};
+
+
+const std::string &
+Event::getAttrName(Attr attr) const
+{
+ if (attr<0 || attr>=ATTR_MAX) {
+ STACK_ADD;
+ throw(Exception(EXCEPTION_MANDATORY, EINVAL, "invalid attribute"));
+ }
+ return attr_names[attr];
+}
+
+
+typedef std::pair<Event::Attr,Event::AttrType> tpair;
+static std::vector<tpair> attrs[Event::TYPE_MAX];
+
+#define apush(etype,attr,atype) \
+ attrs[etype].push_back(tpair(attr,atype))
+
+static bool attrs_inited = false;
+
+static void init_attrs(void)
+{
+@@@{
+ for my $t (getTypes $event) {
+ my $tu = uc $t;
+ selectType $event '_common_';
+ for (getFields $event) {
+ my $fu = uc $_;
+ my $f = selectField $event $_;
+ my $ftu = uc "$f->{type}_T";
+ gen "\tapush(Event::$tu,Event::$fu,Event::$ftu);\n";
+ }
+ selectType $event $t;
+ for (getFields $event) {
+ my $fu = uc $_;
+ my $f = selectField $event $_;
+ my $ftu = uc "$f->{type}_T";
+ gen "\tapush(Event::$tu,Event::$fu,Event::$ftu);\n";
+ }
+ }
+@@@}
+}
+
+std::vector<std::pair<Event::Attr,Event::AttrType> > const & Event::getAttrs(void) const
+{
+ if (type<0 || type>=TYPE_MAX) {
+ STACK_ADD;
+ throw(Exception(EXCEPTION_MANDATORY, EINVAL, "invalid event type"));
+ }
+
+ /* FIXME: thread safety */
+ if (!attrs_inited) {
+ init_attrs();
+ attrs_inited = true;
+ }
+
+ return attrs[type];
+}
+
+
+void
+Event::destroyFlesh(void *in)
+{
+ edg_wll_FreeEvent((edg_wll_Event *) in);
+ free(in);
+}
+
+EWL_END_NAMESPACE;
--- /dev/null
+#ident "$Header$"
+
+/**
+ * @file Job.cpp
+ * @version $Revision$
+ */
+
+
+#include <errno.h>
+#include <stdio.h>
+#include <string.h>
+
+#include <string>
+
+#include "Job.h"
+#include "glite/wms/jobid/JobIdExceptions.h"
+#include "LoggingExceptions.h"
+
+#include "glite/lb/consumer.h"
+#include "glite/lb/context-int.h"
+
+EWL_BEGIN_NAMESPACE;
+
+#define CLASS_PREFIX "edg::workload::logging::Job::"
+
+const int Job::STAT_CLASSADS = EDG_WLL_STAT_CLASSADS;
+const int Job::STAT_CHILDREN = EDG_WLL_STAT_CHILDREN;
+const int Job::STAT_CHILDSTAT = EDG_WLL_STAT_CHILDSTAT;
+
+Job::Job(void)
+{
+}
+
+
+Job::Job(const edg::workload::common::jobid::JobId &in)
+{
+ try {
+ jobId = in;
+ } catch (Exception &e) {
+ STACK_ADD;
+ throw;
+ }
+}
+
+
+Job::~Job(void)
+{
+}
+
+
+Job & Job::operator= (const edg::workload::common::jobid::JobId &in)
+{
+ try {
+ jobId = in;
+ return *this;
+ } catch (Exception &) {
+ STACK_ADD;
+ throw;
+ }
+}
+
+
+JobStatus
+Job::status(int flags) const
+{
+ JobStatus jobStatus;
+
+ try {
+ edg_wll_JobStat *cstat = jobStatus.c_ptr();
+ int ret = edg_wll_JobStatus(server.getContext(),
+ jobId, // automagically converted by member operator
+ flags,
+ cstat);
+ check_result(ret,
+ server.getContext(),
+ "edg_wll_JobStatus");
+
+/* XXX the enums match due to automatic generation */
+ jobStatus.status = (JobStatus::Code) cstat->state;
+
+ return(jobStatus);
+
+ } catch (Exception &e) {
+ STACK_ADD;
+ throw;
+ }
+}
+
+
+void
+Job::log(std::vector<Event> &eventList) const
+{
+ edg_wll_Event *events = NULL,*ev;
+ int result, qresults_param;
+ char *errstr = NULL;
+ edg_wll_Context context;
+
+ try {
+ context = server.getContext();
+ result = edg_wll_JobLog(context, jobId, &events);
+ if (result == E2BIG) {
+ edg_wll_Error(context, NULL, &errstr);
+ check_result(edg_wll_GetParam(context,
+ EDG_WLL_PARAM_QUERY_RESULTS, &qresults_param),
+ context,
+ "edg_wll_GetParam(EDG_WLL_PARAM_QUERY_RESULTS)");
+ if (qresults_param != EDG_WLL_QUERYRES_LIMITED) {
+ edg_wll_SetError(context, result, errstr);
+ check_result(result, context,"edg_wll_JobLog");
+ }
+ } else {
+ check_result(result, context,"edg_wll_JobLog");
+ }
+
+ for (int i=0; events[i].type != EDG_WLL_EVENT_UNDEF; i++) {
+ ev = (edg_wll_Event *) malloc(sizeof *ev);
+ memcpy(ev,events+i,sizeof *ev);
+ eventList.push_back(Event(ev));
+ }
+
+ free(events);
+
+ if (result) {
+ edg_wll_SetError(context, result, errstr);
+ check_result(result, context,"edg_wll_JobLog");
+ }
+ } catch (Exception &e) {
+ if(errstr) free(errstr);
+
+ STACK_ADD;
+ throw;
+ }
+
+}
+
+
+const std::vector<Event>
+Job::log(void) const
+{
+ std::vector<Event> eventList;
+
+ log(eventList);
+ return(eventList);
+}
+
+
+const std::pair<std::string,u_int16_t>
+Job::queryListener(std::string const & name) const
+{
+ std::string host;
+ char *c_host = NULL;
+ uint16_t port;
+
+ try {
+ int ret = edg_wll_QueryListener(server.getContext(),
+ jobId,
+ name.c_str(),
+ &c_host,
+ &port);
+ check_result(ret,
+ server.getContext(),
+ "edg_wll_QueryListener");
+
+ host = c_host;
+ free(c_host);
+ return(std::pair<std::string,u_int16_t>(host,port));
+
+ } catch (Exception &e) {
+ if(c_host) free(c_host);
+ STACK_ADD;
+ throw;
+ }
+}
+
+
+void Job::setParam(edg_wll_ContextParam par, int val)
+{
+ server.setParam(par,val);
+}
+
+void Job::setParam(edg_wll_ContextParam par, const std::string val)
+{
+ server.setParam(par,val);
+}
+
+void Job::setParam(edg_wll_ContextParam par, const struct timeval & val)
+{
+ server.setParam(par,val);
+}
+
+
+int Job::getParamInt(edg_wll_ContextParam par) const
+{
+ return server.getParamInt(par);
+}
+
+std::string Job::getParamString(edg_wll_ContextParam par) const
+{
+ return server.getParamString(par);
+}
+
+struct timeval Job::getParamTime(edg_wll_ContextParam par) const
+{
+ return server.getParamTime(par);
+}
+
+
+
+EWL_END_NAMESPACE;
--- /dev/null
+#include <utility>
+#include <vector>
+#include <string>
+#include <errno.h>
+#include <stdlib.h>
+
+#include "JobStatus.h"
+#include "LoggingExceptions.h"
+#include "glite/wms/jobid/JobId.h"
+
+#include "glite/lb/consumer.h"
+
+
+EWL_BEGIN_NAMESPACE;
+
+#define CLASS_PREFIX "edg::workload::logging::JobStatus::"
+
+@@@{
+sub typeswitch {
+ my ($ftype,$ctype,$resc) = @_;
+ local $_;
+
+ $resc = "break;" unless $resc;
+
+ gen $indent."switch (attr) {\n";
+ selectType $status $ftype;
+ for (getFields $status) {
+ my $f = selectField $status $_;
+ if($f->{type} eq $ctype) {
+ my $fnu = $f->{name};
+ $fnu =~ s/([a-z])([A-Z])/$1_$2/g;
+ $fnu = uc $fnu;
+ my $cname = getName $f 'C';
+ gen "$indent\tcase JobStatus::$fnu: return cstat->$cname;\n"
+ };
+ # XXX: when there are conversion functions, we may get these as strings as well
+ #elsif (($f->{type} eq "int") &&
+ # ($ctype eq "string") &&
+ # $f->{codes}) {
+ # my $fnu = $f->{name};
+ # $fnu =~ s/([a-z])([A-Z])/$1_$2/g;
+ # $fnu = uc $fnu;
+ # my $cname = getName $f 'C';
+ # my $fn = $ftype eq '_common_' ? "" : ucfirst $ftype;
+ # my $c = $fn . ucfirst $f->{name};
+ # $cast = ($c eq 'Level') ? "(edg_wll_Level)" : "";
+ # gen "$indent\tcase JobStatus::$fnu: return((const char *)edg_wll_${c}ToString(${cast}cstat->$cname));\n"; }
+ }
+ gen "$indent\tdefault: $resc\n" if $resc;
+ gen "$indent\}\n";
+}
+@@@}
+
+JobStatus::JobStatus(void)
+{
+ status = UNDEF;
+ flesh = 0;
+}
+
+JobStatus::JobStatus(const JobStatus & in)
+{
+ status = in.status;
+ flesh = in.flesh;
+ if (flesh) flesh->use();
+}
+
+JobStatus &
+JobStatus::operator=(const JobStatus & in)
+{
+ if (flesh) flesh->release();
+ status = in.status;
+ flesh = in.flesh;
+ if (flesh) flesh->use();
+ return *this;
+}
+
+JobStatus::JobStatus(const edg_wll_JobStat & in)
+{
+ status = (Code)in.state;
+ flesh = new CountRef<JobStatus>((void*)&in);
+}
+
+JobStatus &
+JobStatus::operator=(const edg_wll_JobStat & in)
+{
+ if(flesh)
+ flesh->release();
+ status = (Code)in.state;
+ flesh = new CountRef<JobStatus>((void*)&in);
+ return(*this);
+}
+
+JobStatus::~JobStatus()
+{
+ if (flesh) flesh->release();
+}
+
+edg_wll_JobStat *
+JobStatus::c_ptr(void)
+{
+ edg_wll_JobStat *s;
+
+ if(flesh)
+ return((edg_wll_JobStat*)flesh->ptr);
+
+ s = new edg_wll_JobStat;
+ // XXX - is it neccessary? new should throw exception itself...
+ if(!s) throw(Exception(EXCEPTION_MANDATORY,
+ ENOMEM,
+ "out of memory allocating c-struct for JobStatus"));
+
+ edg_wll_InitStatus(s);
+ flesh = new CountRef<JobStatus>((void*)s);
+ return(s);
+}
+
+
+static std::string const names[JobStatus::CODE_MAX] = {
+ "undefined",
+@@@{
+ for (sort { $status->{order}->{$a} <=> $status->{order}->{$b} }
+ $status->getTypes)
+ {
+ gen "\t\"$_\",\n";
+ }
+@@@}
+};
+
+const std::string& JobStatus::name(void) const
+{
+ if (status<0 || status>=CODE_MAX) {
+ STACK_ADD;
+ throw(Exception(EXCEPTION_MANDATORY,
+ EINVAL,
+ "status code invalid"));
+ }
+ return names[status];
+}
+
+int JobStatus::getValInt(JobStatus::Attr attr) const
+{
+ edg_wll_JobStat const *cstat = (edg_wll_JobStat *) flesh->ptr;
+@@@{
+ $indent = "\t";
+ typeswitch '_common_','int';
+@@@}
+
+ STACK_ADD;
+ throw(Exception(EXCEPTION_MANDATORY,
+ ENOENT,
+ "no such attribute"));
+ return -1; /* make gcc shut up -- never returns */
+}
+
+bool JobStatus::getValBool(JobStatus::Attr attr) const
+{
+ edg_wll_JobStat const *cstat = (edg_wll_JobStat *) flesh->ptr;
+@@@{
+ $indent = "\t";
+ typeswitch '_common_','bool';
+@@@}
+
+ STACK_ADD;
+ throw(Exception(EXCEPTION_MANDATORY,
+ ENOENT,
+ "no such attribute"));
+ return -1; /* make gcc shut up -- never returns */
+}
+
+static const char *
+get_string_val(const edg_wll_JobStat *cstat,JobStatus::Attr attr)
+{
+@@@{
+ $indent = "\t";
+ typeswitch '_common_','string';
+@@@}
+ STACK_ADD;
+ throw(Exception(EXCEPTION_MANDATORY,
+ ENOENT,
+ "no such attribute"));
+ return 0; /* make gcc shut up -- never returns */
+}
+
+std::string
+JobStatus::getValString(JobStatus::Attr attr) const
+{
+ edg_wll_JobStat const *cstat = (edg_wll_JobStat *) flesh->ptr;
+ std::string ret;
+
+ try{
+ const char *s = get_string_val(cstat,attr);
+ if (s) ret.assign(s);
+ return ret;
+ } catch (Exception &e) {
+ STACK_ADD;
+ throw;
+ }
+}
+
+
+struct timeval
+JobStatus::getValTime(Attr attr) const
+{
+ edg_wll_JobStat const *cstat = (edg_wll_JobStat *) flesh->ptr;
+
+@@@{
+ $indent = "\t";
+ typeswitch '_common_','timeval';
+@@@}
+ STACK_ADD;
+ throw(Exception(EXCEPTION_MANDATORY,
+ ENOENT,
+ "no such attribute"));
+}
+
+
+const
+edg_wlc_JobId
+get_val_jobid(edg_wll_JobStat const *cstat, JobStatus::Attr attr)
+{
+@@@{
+ $indent = "\t";
+ typeswitch '_common_','jobid';
+@@@}
+ STACK_ADD;
+ throw(Exception(EXCEPTION_MANDATORY,
+ ENOENT,
+ "no such attribute"));
+ return 0; /* make gcc shut up -- never returns */
+}
+
+
+const
+edg::workload::common::jobid::JobId
+JobStatus::getValJobId(Attr attr) const
+{
+ edg_wll_JobStat const *cstat = (edg_wll_JobStat *) flesh->ptr;
+
+ try {
+ edg_wlc_JobId job_id = get_val_jobid(cstat, attr);
+ return(edg::workload::common::jobid::JobId(job_id));
+ }
+ catch(Exception &e) {
+ STACK_ADD;
+ throw;
+ }
+}
+
+const
+int *
+get_val_intlist(edg_wll_JobStat const *cstat, JobStatus::Attr attr)
+{
+@@@{
+ $indent = "\t";
+ typeswitch '_common_','intlist';
+@@@}
+ STACK_ADD;
+ throw(Exception(EXCEPTION_MANDATORY,
+ ENOENT,
+ "no such attribute"));
+ return 0; /* make gcc shut up -- never returns */
+}
+
+
+const
+std::vector<int>
+JobStatus::getValIntList(Attr attr) const
+{
+ edg_wll_JobStat const *cstat = (edg_wll_JobStat *) flesh->ptr;
+
+ std::vector<int> result;
+ const int *r;
+
+ try {
+ r = get_val_intlist(cstat, attr);
+ if(r)
+ for(int i = 1; i <= r[0]; i++)
+ result.push_back(r[i]);
+ } catch(Exception &e) {
+ STACK_ADD;
+ throw;
+ }
+ return result;
+}
+
+
+char ** const
+get_val_stringlist(edg_wll_JobStat const *cstat, JobStatus::Attr attr)
+{
+@@@{
+ $indent = "\t";
+ typeswitch '_common_','strlist';
+@@@}
+ STACK_ADD;
+ throw(Exception(EXCEPTION_MANDATORY,
+ ENOENT,
+ "no such attribute"));
+ return 0; /* make gcc shut up -- never returns */
+}
+
+
+const
+std::vector<std::string>
+JobStatus::getValStringList(Attr attr) const
+{
+ edg_wll_JobStat const *cstat = (edg_wll_JobStat *) flesh->ptr;
+
+ std::vector<std::string> result;
+ char **r , **p;
+
+ try {
+ r = (char**)get_val_stringlist(cstat, attr);
+ if(r)
+ for(p = r; *p; p++)
+ result.push_back(std::string(*p));
+ } catch(Exception &e) {
+ STACK_ADD;
+ throw;
+ }
+ return result;
+}
+
+
+edg_wll_TagValue * const
+get_val_taglist(edg_wll_JobStat const *cstat, JobStatus::Attr attr)
+{
+@@@{
+ $indent = "\t";
+ typeswitch '_common_','taglist';
+@@@}
+ STACK_ADD;
+ throw(Exception(EXCEPTION_MANDATORY,
+ ENOENT,
+ "no such attribute"));
+ return 0; /* make gcc shut up -- never returns */
+}
+
+
+const
+std::vector<std::pair<std::string,std::string> >
+JobStatus::getValTagList(Attr attr) const
+{
+ edg_wll_JobStat const *cstat = (edg_wll_JobStat *) flesh->ptr;
+
+ std::vector<std::pair<std::string,std::string> > result;
+ edg_wll_TagValue *r , *p;
+
+ try {
+ r = get_val_taglist(cstat, attr);
+ if(r)
+ for(p = r; p->tag ; p++)
+ result.push_back(std::pair<std::string,std::string>
+ (std::string(p->tag),std::string(p->value)));
+ } catch(Exception &e) {
+ STACK_ADD;
+ throw;
+ }
+ return result;
+}
+
+
+const
+edg_wll_JobStat *
+get_val_stslist(edg_wll_JobStat const *cstat, JobStatus::Attr attr)
+{
+@@@{
+ $indent = "\t";
+ typeswitch '_common_','stslist';
+@@@}
+ STACK_ADD;
+ throw(Exception(EXCEPTION_MANDATORY,
+ ENOENT,
+ "no such attribute"));
+ return 0; /* make gcc shut up -- never returns */
+}
+
+
+const
+std::vector<JobStatus>
+JobStatus::getValJobStatusList(Attr attr) const
+{
+ edg_wll_JobStat const *cstat = (edg_wll_JobStat *) flesh->ptr;
+
+ std::vector<JobStatus> result;
+ const edg_wll_JobStat *r, *p;
+
+ try {
+ r = get_val_stslist(cstat, attr);
+ if(r)
+ for(p=r; p->state != EDG_WLL_JOB_UNDEF; p++) {
+ edg_wll_JobStat *jsep = new edg_wll_JobStat;
+ if (!edg_wll_CpyStatus(p,jsep)) {
+ STACK_ADD;
+ throw(Exception(EXCEPTION_MANDATORY,
+ ENOMEM,
+ "cannot copy edg_wll_JobStat"));
+ }
+ result.push_back(JobStatus(*jsep));
+ }
+ } catch(Exception &e) {
+ STACK_ADD;
+ throw;
+ }
+ return(result);
+}
+
+
+static std::string const attr_names[JobStatus::ATTR_MAX] = {
+@@@{
+ for (sort {$a cmp $b} getAllFields $status) {
+ gen "\t\"$_\",\n";
+ }
+@@@}
+};
+
+const std::string &
+JobStatus::getAttrName(JobStatus::Attr attr) const
+{
+ if (attr<0 || attr>=ATTR_MAX) {
+ STACK_ADD;
+ throw(Exception(EXCEPTION_MANDATORY,
+ ENOENT,
+ "no such attribute"));
+ }
+
+ return attr_names[attr];
+}
+
+
+typedef std::pair<JobStatus::Attr,JobStatus::AttrType> tpair;
+static std::vector<tpair> attrs;
+
+static bool attrs_inited = false;
+
+static void init_attrs(void)
+{
+/* XXX: currently only common attributes in JobStatus */
+@@@{
+ selectType $status '_common_';
+ for (getFields $status) {
+ my $fu = $_;
+ my $f = selectField $status $_;
+ my $ftu = uc "$f->{type}_T";
+ $fu =~ s/([a-z])([A-Z])/$1_$2/g;
+ $fu = uc $fu;
+
+ gen "\tattrs.push_back(tpair(JobStatus::$fu,JobStatus::$ftu));\n";
+ }
+@@@}
+}
+
+
+const std::vector<tpair>&
+JobStatus::getAttrs(void) const
+{
+ if (status<0 || status>=CODE_MAX) {
+ STACK_ADD;
+ throw(Exception(EXCEPTION_MANDATORY,
+ EINVAL,
+ "status code invalid"));
+ }
+
+/* FIXME: thread safety */
+ if (!attrs_inited) {
+ init_attrs();
+ attrs_inited = true;
+ }
+ return attrs;
+}
+
+void
+JobStatus::destroyFlesh(void *p)
+{
+ edg_wll_JobStat *stat = (edg_wll_JobStat *) p;
+ if (stat) {
+ edg_wll_FreeStatus(stat);
+ free(stat);
+ }
+}
+
+EWL_END_NAMESPACE;
--- /dev/null
+#ident "$Header$"
+
+/**
+ * @file Notification.cpp
+ * @version $Revision$
+ */
+
+#include <errno.h>
+#include <stdio.h>
+#include <string.h>
+
+#include <string>
+#include <vector>
+
+#include "Notification.h"
+#include "JobStatus.h"
+#include "LoggingExceptions.h"
+#include "ServerConnection.h"
+
+#include "glite/lb/notifid.h"
+#include "glite/lb/notification.h"
+
+EWL_BEGIN_NAMESPACE;
+
+#define CLASS_PREFIX "edg::workload::logging::Notification::"
+
+/* external prototypes */
+extern edg_wll_QueryRec **
+convertQueryVectorExt(const std::vector<std::vector<edg::workload::logging::client::QueryRecord> > &);
+
+extern void
+freeQueryRecVector(edg_wll_QueryRec *);
+
+/* Constructors */
+Notification::Notification(void)
+{
+ try {
+ int ret = edg_wll_InitContext(&ctx);
+ check_result(ret,ctx,"edg_wll_InitContext");
+ } catch (Exception &e) {
+ STACK_ADD;
+ throw;
+ }
+}
+
+Notification::Notification(const std::string notifid_str)
+{
+ try {
+ int ret = edg_wll_InitContext(&ctx);
+ check_result(ret,ctx,"edg_wll_InitContext");
+ ret = edg_wll_NotifIdParse(notifid_str.c_str(),¬ifId);
+ check_result(ret,ctx,"edg_wll_NotifIdParse");
+ } catch (Exception &e) {
+ STACK_ADD;
+ throw;
+ }
+}
+
+Notification::Notification(const std::string host,const u_int16_t port)
+{
+ try {
+ int ret = edg_wll_InitContext(&ctx);
+ check_result(ret,ctx,"edg_wll_InitContext");
+ edg_wll_SetParam(ctx, EDG_WLL_PARAM_NOTIF_SERVER, host.c_str());
+ edg_wll_SetParam(ctx, EDG_WLL_PARAM_NOTIF_SERVER_PORT, port);
+ ret = edg_wll_NotifIdCreate(host.c_str(),port,¬ifId);
+ check_result(ret,ctx,"edg_wll_NotifIdCreate");
+ } catch (Exception &e) {
+ STACK_ADD;
+ throw;
+ }
+}
+
+/* Destructor */
+Notification::~Notification(void)
+{
+ try {
+ edg_wll_FreeContext(ctx);
+ } catch (Exception &e) {
+ STACK_ADD;
+ throw;
+ }
+}
+
+/* Methods */
+std::string
+Notification::getNotifId(void) const
+{
+ try {
+ std::string notifid_str = edg_wll_NotifIdUnparse(notifId);
+ return(notifid_str);
+ } catch (Exception &e) {
+ STACK_ADD;
+ throw;
+ }
+}
+
+time_t
+Notification::getValid(void) const
+{
+ return(valid);
+}
+
+int
+Notification::getFd(void) const
+{
+ try {
+ int ret = edg_wll_NotifGetFd(ctx);
+ check_result(ret,ctx,"edg_wll_NotifGetFd");
+ return(ret);
+ } catch (Exception &e) {
+ STACK_ADD;
+ throw;
+ }
+}
+
+void
+Notification::addJob(const edg::workload::common::jobid::JobId &jobId)
+{
+ std::vector<edg::workload::common::jobid::JobId>::iterator it;
+
+ try {
+ for( it = jobs.begin(); it != jobs.end(); it++ ) {
+ if ( (*it).toString() == jobId.toString() ) {
+ STACK_ADD;
+ throw Exception(EXCEPTION_MANDATORY, EINVAL, "job already exists");
+ }
+ }
+ jobs.push_back(jobId);
+
+ } catch (Exception &e) {
+ STACK_ADD;
+ throw;
+ }
+}
+
+void
+Notification::removeJob(const edg::workload::common::jobid::JobId &jobId)
+{
+ std::vector<edg::workload::common::jobid::JobId>::iterator it;
+ int removed = 0;
+
+ try {
+ for( it = jobs.begin(); it != jobs.end(); it++ ) {
+ if ( (*it).toString() == jobId.toString() ) {
+ jobs.erase(it);
+ removed += 1;
+// break;
+ }
+ }
+ } catch (Exception &e) {
+ STACK_ADD;
+ throw;
+ }
+
+ if (removed == 0) {
+ STACK_ADD;
+ throw Exception(EXCEPTION_MANDATORY, EINVAL, "no job to remove");
+ }
+}
+
+std::string
+Notification::getJobs(void)
+{
+ std::vector<edg::workload::common::jobid::JobId>::iterator it;
+ std::string ret="";
+
+ try {
+ for( it = jobs.begin(); it != jobs.end(); it++ ) {
+ ret += (*it).toString();
+ ret += "\n";
+ }
+ return ret;
+
+ } catch (Exception &e) {
+ STACK_ADD;
+ throw;
+ }
+}
+
+void
+Notification::setStates(const std::vector<edg::workload::logging::client::JobStatus::Code> &jobStates)
+{
+ states = jobStates;
+}
+
+std::string
+Notification::getStates(void)
+{
+ std::vector<edg::workload::logging::client::JobStatus::Code>::iterator it;
+ JobStatus js;
+ std::string ret="";
+
+ try {
+ for( it = states.begin(); it != states.end(); it++ ) {
+ js.status = (*it);
+ ret += js.name();
+ ret += "\n";
+ }
+ return ret;
+
+ } catch (Exception &e) {
+ STACK_ADD;
+ throw;
+ }
+}
+
+void
+Notification::Register(void)
+{
+ int ret = 0;
+ std::vector<edg::workload::common::jobid::JobId>::iterator it;
+ std::vector<edg::workload::logging::client::JobStatus::Code>::iterator its;
+ std::vector<std::vector<edg::workload::logging::client::QueryRecord> > query;
+ edg_wll_QueryRec **conditions = NULL;
+ unsigned i;
+
+ try {
+ /* fill in the query: */
+ for( it = jobs.begin(); it != jobs.end(); it++ ) {
+ std::vector<edg::workload::logging::client::QueryRecord> queryjob;
+
+ QueryRecord r0(QueryRecord::JOBID,QueryRecord::EQUAL,*it);
+ queryjob.push_back(r0);
+
+ for( its = states.begin(); its != states.end(); its++ ) {
+ QueryRecord r(QueryRecord::STATUS,QueryRecord::EQUAL,*its);
+ queryjob.push_back(r);
+ }
+
+ query.push_back(queryjob);
+ }
+ /* convert query to conditions */
+ conditions = convertQueryVectorExt(query);
+ /* register */
+ ret = edg_wll_NotifNew(ctx,conditions,-1,NULL,¬ifId,&valid);
+ check_result(ret,ctx,"edg_wll_NotifNew");
+ /* clean */
+ if (conditions) {
+ for( i = 0; conditions[i]; i++ ) {
+// FIXME: not working :o(
+// freeQueryRecVector(conditions[i]);
+ delete[] conditions[i];
+ }
+ delete[] conditions;
+ }
+ } catch (Exception &e) {
+ /* clean */
+ if (conditions) {
+ for( i = 0; conditions[i]; i++ ) {
+// FIXME: not working :o(
+// freeQueryRecVector(conditions[i]);
+ delete[] conditions[i];
+ }
+ delete[] conditions;
+ }
+ STACK_ADD;
+ throw;
+ }
+}
+
+int Notification::receive(edg::workload::logging::client::JobStatus &jobStatus,timeval &timeout)
+{
+ int ret = 0;
+ edg_wll_JobStat *status = (edg_wll_JobStat *) calloc(1,sizeof(edg_wll_JobStat));
+ if (status == NULL) {
+ STACK_ADD;
+ throw OSException(EXCEPTION_MANDATORY, ENOMEM, "allocating jobStatus");
+ }
+ ret = edg_wll_NotifReceive(ctx,-1,&timeout,status,¬ifId);
+ check_result(ret,ctx,"edg_wll_NotifReceive");
+ jobStatus = JobStatus(*status);
+ return(ret);
+}
+
+EWL_END_NAMESPACE;
--- /dev/null
+//#ident "$Header$"
+
+/**
+ * @file ServerConnection.cpp
+ * @version $Revision$
+ */
+#include <string>
+#include <utility>
+#include <vector>
+
+#include <time.h>
+#include <errno.h>
+#include <stdio.h>
+
+#include <expat.h>
+
+#include "glite/wms/jobid/JobId.h"
+#include "glite/wms/jobid/JobIdExceptions.h"
+#include "glite/lb/context-int.h"
+#include "glite/lb/xml_conversions.h"
+
+#include "ServerConnection.h"
+#include "LoggingExceptions.h"
+
+///using namespace edg::workload::logging;
+
+EWL_BEGIN_NAMESPACE;
+
+/**
+ * definitions of QueryRecord class
+ */
+#define CLASS_PREFIX "edg::workload::logging::QueryRecord::"
+
+
+QueryRecord::QueryRecord(const Attr a,
+ const Op o,
+ const std::string & v)
+ : attr(a), oper(o), state(EDG_WLL_JOB_UNDEF), string_value(v)
+{
+ switch(a) {
+ case OWNER:
+ case LOCATION:
+ case DESTINATION:
+ case HOST:
+ case INSTANCE:
+ break;
+
+ default:
+ STACK_ADD;
+ throw Exception(EXCEPTION_MANDATORY, EINVAL, "invalid value for attribute: " + v);
+ }
+}
+
+
+QueryRecord::QueryRecord(const Attr a,
+ const Op o,
+ const int v)
+ : attr(a), oper(o), state(EDG_WLL_JOB_UNDEF), int_value(v)
+{
+ switch(a) {
+ case DONECODE:
+ case STATUS:
+ case SOURCE:
+ case EVENT_TYPE:
+ case LEVEL:
+ case EXITCODE:
+ break;
+
+ default:
+ STACK_ADD;
+ throw Exception(EXCEPTION_MANDATORY, EINVAL, "attribute is not of integer type");
+ }
+}
+
+
+QueryRecord::QueryRecord(const Attr a,
+ const Op o,
+ const struct timeval& v)
+ : attr(a), oper(o), state(EDG_WLL_JOB_UNDEF), timeval_value(v)
+{
+ switch(a) {
+ case TIME:
+ break;
+
+ default:
+ STACK_ADD;
+ throw Exception(EXCEPTION_MANDATORY, EINVAL, "attribute is not of timeval type");
+ }
+}
+
+
+QueryRecord::QueryRecord(const Attr a,
+ const Op o,
+ const edg::workload::common::jobid::JobId& v)
+ : attr(a), oper(o), state(EDG_WLL_JOB_UNDEF), jobid_value(v)
+{
+ switch(a) {
+ case JOBID:
+ case PARENT:
+ break;
+
+ default:
+ STACK_ADD;
+ throw Exception(EXCEPTION_MANDATORY, EINVAL, "attribute is not of JobId type");
+ }
+}
+
+
+QueryRecord::QueryRecord(const Attr a,
+ const Op o,
+ const int s,
+ const struct timeval &v)
+ : attr(a), oper(o), state(s), timeval_value(v)
+{
+ switch(a) {
+ case TIME:
+ break;
+
+ default:
+ STACK_ADD;
+ throw Exception(EXCEPTION_MANDATORY, EINVAL, "attribute is not of timeval type");
+ }
+}
+
+
+QueryRecord::QueryRecord(const Attr a,
+ const Op o,
+ const std::string &v1,
+ const std::string &v2)
+ : attr(a), oper(o), state(EDG_WLL_JOB_UNDEF), string_value(v1), string_value2(v2)
+{
+ switch(a) {
+ case OWNER:
+ case LOCATION:
+ case DESTINATION:
+ case HOST:
+ case INSTANCE:
+ break;
+
+ default:
+ STACK_ADD;
+ throw Exception(EXCEPTION_MANDATORY, EINVAL, "invalid value for attribute type");
+ }
+ if(o != WITHIN) {
+ STACK_ADD;
+ throw Exception(EXCEPTION_MANDATORY, EINVAL, "only operator WITHIN allowed with two values");
+ }
+}
+
+
+QueryRecord::QueryRecord(const Attr a,
+ const Op o,
+ const int v1,
+ const int v2)
+ : attr(a), oper(o), state(EDG_WLL_JOB_UNDEF), int_value(v1), int_value2(v2)
+{
+ switch(a) {
+ case DONECODE:
+ case STATUS:
+ case SOURCE:
+ case EVENT_TYPE:
+ case LEVEL:
+ case EXITCODE:
+ break;
+
+ default:
+ STACK_ADD;
+ throw Exception(EXCEPTION_MANDATORY, EINVAL, "attribute is not of integer type");
+ }
+ if(o != WITHIN) {
+ STACK_ADD;
+ throw Exception(EXCEPTION_MANDATORY, EINVAL, "only operator WITHIN allowed with two values");
+ }
+}
+
+
+QueryRecord::QueryRecord(const Attr a,
+ const Op o,
+ const struct timeval &v1,
+ const struct timeval &v2)
+ : attr(a), oper(o), state(EDG_WLL_JOB_UNDEF), timeval_value(v1), timeval_value2(v2)
+{
+ switch(a) {
+ case TIME:
+ break;
+
+ default:
+ STACK_ADD;
+ throw Exception(EXCEPTION_MANDATORY, EINVAL, "attribute is not of timeval type");
+ }
+ if(o != WITHIN) {
+ STACK_ADD;
+ throw Exception(EXCEPTION_MANDATORY, EINVAL, "only operator WITHIN allowed with two values");
+ }
+}
+
+
+QueryRecord::QueryRecord(const Attr a,
+ const Op o,
+ const int s,
+ const struct timeval &v1,
+ const struct timeval &v2)
+ : attr(a), oper(o), state(s), timeval_value(v1), timeval_value2(v2)
+{
+ switch(a) {
+ case TIME:
+ break;
+
+ default:
+ STACK_ADD;
+ throw Exception(EXCEPTION_MANDATORY, EINVAL, "attribute is not of timeval type");
+ }
+ if(o != WITHIN) {
+ STACK_ADD;
+ throw Exception(EXCEPTION_MANDATORY, EINVAL, "only operator WITHIN allowed with two values");
+ }
+}
+
+
+QueryRecord::QueryRecord(const std::string &tag,
+ const Op o,
+ const std::string &val)
+ : attr(USERTAG), oper(o), tag_name(tag), state(EDG_WLL_JOB_UNDEF), string_value(val)
+{
+}
+
+
+QueryRecord::QueryRecord(const std::string &tag,
+ const Op o,
+ const std::string &v1,
+ const std::string &v2)
+ : attr(USERTAG), oper(o), tag_name(tag), state(EDG_WLL_JOB_UNDEF),
+ string_value(v1), string_value2(v2)
+
+{
+ if(o != WITHIN) {
+ STACK_ADD;
+ throw Exception(EXCEPTION_MANDATORY, EINVAL, "only operator WITHIN allowed with two values");
+ }
+}
+
+
+QueryRecord::QueryRecord(const QueryRecord &src)
+{
+ attr = src.attr;
+ oper = src.oper;
+
+ switch (attr) {
+
+ case USERTAG:
+ tag_name = src.tag_name;
+
+ case OWNER:
+ case LOCATION:
+ case DESTINATION:
+ case HOST:
+ case INSTANCE:
+ string_value = src.string_value;
+ if(src.oper == WITHIN)
+ string_value2 = src.string_value2;
+ break;
+
+ case DONECODE:
+ case STATUS:
+ case SOURCE:
+ case EVENT_TYPE:
+ case LEVEL:
+ case EXITCODE:
+ int_value = src.int_value;
+ if(src.oper == WITHIN)
+ int_value2 = src.int_value2;
+ break;
+
+ case TIME:
+ timeval_value = src.timeval_value;
+ if(src.oper == WITHIN)
+ timeval_value2 = src.timeval_value2;
+ state = src.state;
+ break;
+
+ case JOBID:
+ jobid_value = src.jobid_value;
+ break;
+
+ default:
+ STACK_ADD;
+ throw Exception(EXCEPTION_MANDATORY, EINVAL, "query attribute not defined");
+ }
+}
+
+
+QueryRecord::QueryRecord() : attr(UNDEF), oper(EQUAL)
+{
+}
+
+
+QueryRecord::~QueryRecord()
+{
+}
+
+
+QueryRecord&
+QueryRecord::operator=(const QueryRecord &src)
+{
+ if(this == &src)
+ return(*this);
+
+ attr = src.attr;
+ oper = src.oper;
+
+ switch (attr) {
+
+ case USERTAG:
+ tag_name = src.tag_name;
+
+ case OWNER:
+ case LOCATION:
+ case DESTINATION:
+ case HOST:
+ case INSTANCE:
+ string_value = src.string_value;
+ if(oper == WITHIN)
+ string_value2 = src.string_value2;
+ break;
+
+ case DONECODE:
+ case STATUS:
+ case SOURCE:
+ case EVENT_TYPE:
+ case LEVEL:
+ case EXITCODE:
+ int_value = src.int_value;
+ if(oper == WITHIN)
+ int_value2 = src.int_value2;
+ break;
+
+ case TIME:
+ timeval_value = src.timeval_value;
+ state = src.state;
+ if(oper == WITHIN)
+ timeval_value2 = src.timeval_value2;
+ break;
+
+ case JOBID:
+ jobid_value = src.jobid_value;
+ break;
+
+ default:
+ STACK_ADD;
+ throw Exception(EXCEPTION_MANDATORY, EINVAL, "query attribute not defined");
+ }
+
+ return *this;
+}
+
+
+QueryRecord::operator edg_wll_QueryRec() const
+{
+ edg_wll_QueryRec out;
+
+ out.attr = edg_wll_QueryAttr(attr);
+ out.op = edg_wll_QueryOp(oper);
+
+ switch (attr) {
+
+ case USERTAG:
+ out.attr_id.tag = strdup(tag_name.c_str());
+
+ case OWNER:
+ case LOCATION:
+ case DESTINATION:
+ case HOST:
+ case INSTANCE:
+ out.value.c = strdup(string_value.c_str());
+ if(oper == WITHIN)
+ out.value2.c = strdup(string_value2.c_str());
+ break;
+
+
+ case DONECODE:
+ case STATUS:
+ case SOURCE:
+ case EVENT_TYPE:
+ case LEVEL:
+ case EXITCODE:
+ out.value.i = int_value;
+ if(oper == WITHIN)
+ out.value2.i = int_value2;
+ break;
+
+ case TIME:
+ out.value.t = timeval_value;
+ out.attr_id.state = (edg_wll_JobStatCode)state;
+ if(oper == WITHIN)
+ out.value2.t = timeval_value2;
+ break;
+
+ case JOBID:
+ out.value.j = jobid_value;
+ break;
+
+ case UNDEF:
+ break;
+
+ default:
+ STACK_ADD;
+ throw Exception(EXCEPTION_MANDATORY, EINVAL, "query attribute not defined");
+ }
+
+ return(out);
+}
+
+const std::string QueryRecord::AttrName(const QueryRecord::Attr attr)
+{
+ char *an = edg_wll_query_attrToString(edg_wll_QueryAttr(attr));
+ std::string ret(an);
+ free(an);
+ return ret;
+}
+
+
+/**
+ * definitions of ServerConnection class
+ */
+#undef CLASS_PREFIX
+#define CLASS_PREFIX "edg::workload::logging::ServerConnection::"
+
+ServerConnection::ServerConnection()
+{
+ int ret;
+ edg_wll_Context tmp_context;
+
+ if((ret=edg_wll_InitContext(&tmp_context)) < 0) {
+ STACK_ADD;
+ throw OSException(EXCEPTION_MANDATORY, ret, "initializing context");
+ }
+
+ context = tmp_context;
+}
+
+
+ServerConnection::~ServerConnection()
+{
+ /* no exceptions should be thrown from destructors */
+ edg_wll_FreeContext(context);
+}
+
+
+/********************/
+/* BEGIN DEPRECATED */
+
+ServerConnection::ServerConnection(const std::string &in)
+{
+ STACK_ADD;
+ throw Exception(EXCEPTION_MANDATORY, 0, "method deprecated");
+}
+
+
+void
+ServerConnection::open(const std::string & in)
+{
+ STACK_ADD;
+ throw Exception(EXCEPTION_MANDATORY, 0, "method deprecated");
+}
+
+
+void
+ServerConnection::close(void)
+{
+ STACK_ADD;
+ throw Exception(EXCEPTION_MANDATORY, 0, "method deprecated");
+}
+
+/* END DEPRECATED */
+/******************/
+
+
+void
+ServerConnection::setQueryServer(const std::string& server, int port)
+{
+ check_result(edg_wll_SetParamString(context,
+ EDG_WLL_PARAM_QUERY_SERVER,
+ server.c_str()),
+ context,
+ "setting query server address");
+ check_result(edg_wll_SetParamInt(context,
+ EDG_WLL_PARAM_QUERY_SERVER_PORT,
+ port),
+ context,
+ "setting query server port");
+}
+
+
+void
+ServerConnection::setQueryTimeout(int timeout)
+{
+ check_result(edg_wll_SetParamInt(context,
+ EDG_WLL_PARAM_QUERY_TIMEOUT,
+ timeout),
+ context,
+ "setting query timeout");
+}
+
+
+void ServerConnection::setX509Proxy(const std::string& proxy)
+{
+ check_result(edg_wll_SetParamString(context,
+ EDG_WLL_PARAM_X509_PROXY,
+ proxy.c_str()),
+ context,
+ "setting X509 proxy");
+}
+
+
+void ServerConnection::setX509Cert(const std::string& cert, const std::string& key)
+{
+ check_result(edg_wll_SetParamString(context,
+ EDG_WLL_PARAM_X509_CERT,
+ cert.c_str()),
+ context,
+ "setting X509 certificate");
+ check_result(edg_wll_SetParamString(context,
+ EDG_WLL_PARAM_X509_KEY,
+ key.c_str()),
+ context,
+ "setting X509 key");
+}
+
+
+void
+ServerConnection::setQueryEventsLimit(int max) {
+ check_result(edg_wll_SetParamInt(context,
+ EDG_WLL_PARAM_QUERY_EVENTS_LIMIT,
+ max),
+ context,
+ "setting query events limit");
+}
+
+void
+ServerConnection::setQueryJobsLimit(int max) {
+ check_result(edg_wll_SetParamInt(context,
+ EDG_WLL_PARAM_QUERY_JOBS_LIMIT,
+ max),
+ context,
+ "setting query jobs limit");
+}
+
+
+std::pair<std::string, int>
+ServerConnection::getQueryServer() const
+{
+ /* FIXME: not implemented in C API */
+ STACK_ADD;
+ throw Exception(EXCEPTION_MANDATORY, 0, "method not implemented");
+}
+
+
+int
+ServerConnection::getQueryTimeout() const
+{
+ /* FIXME: not implemented in C API */
+ STACK_ADD;
+ throw Exception(EXCEPTION_MANDATORY, 0, "method not implemented");
+}
+
+
+std::string
+ServerConnection::getX509Proxy() const
+{
+ /* FIXME: not implemented in C API */
+ STACK_ADD;
+ throw Exception(EXCEPTION_MANDATORY, 0, "method not implemented");
+}
+
+
+std::pair<std::string, std::string>
+ServerConnection::getX509Cert() const
+{
+ /* FIXME: not implemented in C API */
+ STACK_ADD;
+ throw Exception(EXCEPTION_MANDATORY, 0, "method not implemented");
+}
+
+// static
+void freeQueryRecVector(edg_wll_QueryRec *v)
+{
+ for(; v->attr != EDG_WLL_QUERY_ATTR_UNDEF; v++)
+ edg_wll_QueryRecFree(v);
+}
+
+std::vector<std::vector<std::pair<QueryRecord::Attr,std::string> > >
+ServerConnection::getIndexedAttrs(void) {
+ edg_wll_QueryRec **recs;
+ int i,j;
+ std::vector<std::vector<std::pair<QueryRecord::Attr,std::string> > > out;
+
+ check_result(edg_wll_GetIndexedAttrs(context,&recs),context,
+ "edg_wll_GetIndexedAttrs()");
+
+ for (i=0; recs[i]; i++) {
+ std::vector<std::pair<QueryRecord::Attr,std::string> > idx;
+ for (j=0; recs[i][j].attr; j++) {
+ char *s = strdup("");
+ if (recs[i][j].attr == EDG_WLL_QUERY_ATTR_USERTAG)
+ s = strdup(recs[i][j].attr_id.tag);
+ else if (recs[i][j].attr == EDG_WLL_QUERY_ATTR_TIME)
+ s = edg_wll_StatToString(recs[i][j].attr_id.state);
+ idx.push_back(
+ std::pair<QueryRecord::Attr,std::string>(
+ QueryRecord::Attr(recs[i][j].attr),s)
+ );
+ free(s);
+ }
+ freeQueryRecVector(recs[i]);
+ out.push_back(idx);
+ }
+ free(recs);
+ return out;
+}
+
+
+
+
+edg_wll_QueryRec *
+convertQueryVector(const std::vector<QueryRecord> &in)
+{
+ unsigned i;
+ edg_wll_QueryRec *out = new edg_wll_QueryRec[in.size() + 1];
+ QueryRecord empty;
+
+ if(out == NULL) {
+ STACK_ADD;
+ throw OSException(EXCEPTION_MANDATORY, ENOMEM, "allocating vector for conversion");
+ }
+
+ try {
+ for(i = 0; i < in.size(); i++) {
+ out[i] = in[i];
+ }
+ out[i] = empty;
+ } catch (Exception &e) {
+ STACK_ADD;
+ throw;
+ }
+ return(out);
+}
+
+
+edg_wll_QueryRec **
+convertQueryVectorExt(const std::vector<std::vector<QueryRecord> > &in)
+{
+ unsigned i;
+ edg_wll_QueryRec **out = new (edg_wll_QueryRec*)[in.size() + 1];
+
+ if(out == NULL) {
+ STACK_ADD;
+ throw OSException(EXCEPTION_MANDATORY, ENOMEM, "allocating vector for conversion");
+ }
+
+ try {
+ for(i = 0; i < in.size(); i++) {
+ out[i] = convertQueryVector(in[i]);
+ }
+ out[i] = NULL;
+ } catch (Exception &e) {
+ STACK_ADD;
+ throw;
+ }
+ return(out);
+}
+
+void
+ServerConnection::queryEvents(const std::vector<QueryRecord>& job_cond,
+ const std::vector<QueryRecord>& event_cond,
+ std::vector<Event> & eventList) const
+{
+ edg_wll_QueryRec *job_rec = NULL, *event_rec = NULL;
+ edg_wll_Event *events = NULL;
+ unsigned i;
+ int result, qresults_param;
+ char *errstr = NULL;
+
+ /* convert input */
+ try {
+ job_rec = convertQueryVector(job_cond);
+ event_rec = convertQueryVector(event_cond);
+
+ /* do the query */
+
+ result = edg_wll_QueryEvents(context, job_rec, event_rec, &events);
+ if (result == E2BIG) {
+ edg_wll_Error(context, NULL, &errstr);
+ check_result(edg_wll_GetParam(context,
+ EDG_WLL_PARAM_QUERY_RESULTS, &qresults_param),
+ context,
+ "edg_wll_GetParam(EDG_WLL_PARAM_QUERY_RESULTS)");
+ if (qresults_param != EDG_WLL_QUERYRES_LIMITED) {
+ edg_wll_SetError(context, result, errstr);
+ check_result(result, context,"edg_wll_QueryEvents");
+ }
+ } else {
+ check_result(result, context,"edg_wll_QueryEvents");
+ }
+
+ /* convert output */
+ for (i=0; events[i].type != EDG_WLL_EVENT_UNDEF; i++) {
+ edg_wll_Event *ev = (edg_wll_Event *) malloc(sizeof *ev);
+ memcpy(ev,events+i,sizeof *ev);
+ Event e(ev);
+
+ eventList.push_back(e);
+ }
+
+ if (result) {
+ edg_wll_SetError(context, result, errstr);
+ check_result(result, context,"edg_wll_QueryEvents");
+ }
+
+ free(events);
+ delete[] job_rec;
+ delete[] event_rec;
+
+ } catch(Exception &e) {
+ if(job_rec) delete[] job_rec;
+ if(event_rec) delete[] event_rec;
+ if(events) free(events);
+ if(errstr) free(errstr);
+
+ STACK_ADD;
+ throw;
+ }
+}
+
+
+const std::vector<Event>
+ServerConnection::queryEvents(const std::vector<QueryRecord>& job_cond,
+ const std::vector<QueryRecord>& event_cond) const
+{
+ std::vector<Event> eventList;
+
+ queryEvents(job_cond, event_cond,eventList);
+ return eventList;
+}
+
+const std::list<Event>
+ServerConnection::queryEventsList(const std::vector<QueryRecord>& job_cond,
+ const std::vector<QueryRecord>& event_cond) const
+{
+ std::vector<Event> events;
+
+ queryEvents(job_cond, event_cond, events);
+ return std::list<Event>(events.begin(),events.end());
+}
+
+std::string
+ServerConnection::queryEventsAggregate(const std::vector<QueryRecord>& job_cond,
+ const std::vector<QueryRecord>& event_cond,
+ enum AggOp const op,
+ std::string const attr) const
+{
+ STACK_ADD;
+ throw Exception(EXCEPTION_MANDATORY, 0, "method not implemented");
+ return ""; // gcc warning;
+}
+
+
+void
+ServerConnection::queryEvents(const std::vector<std::vector<QueryRecord> >& job_cond,
+ const std::vector<std::vector<QueryRecord> >& event_cond,
+ std::vector<Event>& eventList) const
+{
+ edg_wll_QueryRec **job_rec = NULL, **event_rec = NULL;
+ edg_wll_Event *events = NULL;
+ unsigned i;
+
+ /* convert input */
+ try {
+ job_rec = convertQueryVectorExt(job_cond);
+ event_rec = convertQueryVectorExt(event_cond);
+
+ /* do the query */
+
+ check_result(edg_wll_QueryEventsExt(context,
+ (const edg_wll_QueryRec**)job_rec,
+ (const edg_wll_QueryRec**)event_rec,
+ &events),
+ context,
+ "edg_wll_QueryEvents");
+
+ /* convert output */
+ for (i=0; events[i].type != EDG_WLL_EVENT_UNDEF; i++) {
+ edg_wll_Event *ev = (edg_wll_Event *) malloc(sizeof *ev);
+ memcpy(ev,events+i,sizeof *ev);
+ Event e(ev);
+
+ eventList.push_back(e);
+ }
+
+ free(events);
+
+ for(i = 0 ; job_rec[i]; i++) delete[] job_rec[i];
+ for(i = 0 ; event_rec[i]; i++) delete[] event_rec[i];
+ delete[] job_rec;
+ delete[] event_rec;
+
+ } catch(Exception &e) {
+
+ if(job_rec) {
+ for(i = 0 ; job_rec[i]; i++) delete[] job_rec[i];
+ delete[] job_rec;
+ }
+ if(event_rec) {
+ for(i = 0 ; event_rec[i]; i++) delete[] event_rec[i];
+ delete[] event_rec;
+ }
+ if(events) free(events);
+
+ STACK_ADD;
+ throw;
+ }
+}
+
+
+const std::vector<Event>
+ServerConnection::queryEvents(const std::vector<std::vector<QueryRecord> >& job_cond,
+ const std::vector<std::vector<QueryRecord> >& event_cond) const
+{
+ std::vector<Event> eventList;
+
+ queryEvents(job_cond, event_cond,eventList);
+ return eventList;
+}
+
+
+void ServerConnection::queryJobs(const std::vector<QueryRecord>& query,
+ std::vector<edg::workload::common::jobid::JobId> & ids) const
+{
+ edg_wll_QueryRec *cond = NULL;
+ edg_wlc_JobId *jobs, *j;
+ int result, qresults_param;
+ char *errstr = NULL;
+
+ try {
+ cond = convertQueryVector(query);
+
+ result = edg_wll_QueryJobs(context, cond, 0, &jobs, NULL);
+ if (result == E2BIG) {
+ edg_wll_Error(context, NULL, &errstr);
+ check_result(edg_wll_GetParam(context,
+ EDG_WLL_PARAM_QUERY_RESULTS, &qresults_param),
+ context,
+ "edg_wll_GetParam(EDG_WLL_PARAM_QUERY_RESULTS)");
+ if (qresults_param != EDG_WLL_QUERYRES_LIMITED) {
+ edg_wll_SetError(context, result, errstr);
+ check_result(result, context,"edg_wll_QueryJobs");
+ }
+ } else {
+ check_result(result, context,"edg_wll_QueryJobs");
+ }
+
+ for(j = jobs; *j; j++)
+ ids.push_back(edg::workload::common::jobid::JobId(*j));
+
+ if (result) {
+ edg_wll_SetError(context, result, errstr);
+ check_result(result, context,"edg_wll_QueryJobs");
+ }
+
+ free(jobs);
+ freeQueryRecVector(cond);
+ delete[] cond;
+
+ } catch (Exception &e) {
+ if(cond) {
+ freeQueryRecVector(cond);
+ delete[] cond;
+ }
+ if (errstr) free(errstr);
+
+ STACK_ADD;
+ throw;
+ }
+}
+
+
+const std::vector<edg::workload::common::jobid::JobId>
+ServerConnection::queryJobs(const std::vector<QueryRecord>& query) const
+{
+ std::vector<edg::workload::common::jobid::JobId> jobList;
+
+ queryJobs(query, jobList);
+ return jobList;
+}
+
+
+void
+ServerConnection::queryJobs(const std::vector<std::vector<QueryRecord> >& query,
+ std::vector<edg::workload::common::jobid::JobId>& ids) const
+{
+ edg_wll_QueryRec **cond = NULL;
+ edg_wlc_JobId *jobs, *j;
+ int result, qresults_param;
+ char *errstr = NULL;
+
+ try {
+ cond = convertQueryVectorExt(query);
+
+ result = edg_wll_QueryJobsExt(context, (const edg_wll_QueryRec**)cond,
+ 0, &jobs, NULL);
+ if (result == E2BIG) {
+ edg_wll_Error(context, NULL, &errstr);
+ check_result(edg_wll_GetParam(context,
+ EDG_WLL_PARAM_QUERY_RESULTS, &qresults_param),
+ context,
+ "edg_wll_GetParam(EDG_WLL_PARAM_QUERY_RESULTS)");
+ if (qresults_param != EDG_WLL_QUERYRES_LIMITED) {
+ edg_wll_SetError(context, result, errstr);
+ check_result(result, context,"edg_wll_QueryJobsExt");
+ }
+ } else {
+ check_result(result, context,"edg_wll_QueryJobsExt");
+ }
+
+ for(j = jobs; *j; j++)
+ ids.push_back(edg::workload::common::jobid::JobId(*j));
+
+ if (result) {
+ edg_wll_SetError(context, result, errstr);
+ check_result(result, context,"edg_wll_QueryJobsExt");
+ }
+
+ free(jobs);
+ {
+ unsigned i;
+
+ for(i = 0; cond[i]; i++) {
+ freeQueryRecVector(cond[i]);
+ delete[] cond[i];
+ }
+ delete[] cond;
+ }
+
+ } catch (Exception &e) {
+ unsigned i;
+ if(cond) {
+ for(i = 0; cond[i]; i++) {
+ freeQueryRecVector(cond[i]);
+ delete[] cond[i];
+ }
+ delete[] cond;
+ }
+ if (errstr) free(errstr);
+
+ STACK_ADD;
+ throw;
+ }
+}
+
+
+const
+std::vector<edg::workload::common::jobid::JobId>
+ServerConnection::queryJobs(const std::vector<std::vector<QueryRecord> >& query) const
+{
+ std::vector<edg::workload::common::jobid::JobId> jobList;
+
+ queryJobs(query, jobList);
+ return jobList;
+}
+
+
+void
+ServerConnection::queryJobStates(const std::vector<QueryRecord>& query,
+ int flags,
+ std::vector<JobStatus> & states) const
+{
+ edg_wll_QueryRec *cond = NULL;
+ edg_wll_JobStat *jobs, *j;
+ int result, qresults_param;
+ char *errstr = NULL;
+
+ try {
+ cond = convertQueryVector(query);
+
+ result = edg_wll_QueryJobs(context, cond, flags, NULL, &jobs);
+ if (result == E2BIG) {
+ edg_wll_Error(context, NULL, &errstr);
+ check_result(edg_wll_GetParam(context,
+ EDG_WLL_PARAM_QUERY_RESULTS, &qresults_param),
+ context,
+ "edg_wll_GetParam(EDG_WLL_PARAM_QUERY_RESULTS)");
+ if (qresults_param != EDG_WLL_QUERYRES_LIMITED) {
+ edg_wll_SetError(context, result, errstr);
+ check_result(result, context,"edg_wll_QueryJobs");
+ }
+ } else {
+ check_result(result, context,"edg_wll_QueryJobs");
+ }
+
+ for(j = jobs; j->state != EDG_WLL_JOB_UNDEF; j++) {
+ edg_wll_JobStat *jsep = new edg_wll_JobStat;
+ if (jsep != NULL) {
+ memcpy(jsep, j, sizeof(*j));
+ states.push_back(JobStatus(*jsep));
+ }
+ }
+
+ if (result) {
+ edg_wll_SetError(context, result, errstr);
+ check_result(result, context,"edg_wll_QueryJobs");
+ }
+
+ delete jobs;
+
+ freeQueryRecVector(cond);
+ delete[] cond;
+
+ } catch (Exception &e) {
+ if(cond) {
+ freeQueryRecVector(cond);
+ delete[] cond;
+ }
+ if (errstr) free(errstr);
+
+ STACK_ADD;
+ throw;
+ }
+}
+
+
+const std::vector<JobStatus>
+ServerConnection::queryJobStates(const std::vector<QueryRecord>& query,
+ int flags) const
+{
+ std::vector<JobStatus> states;
+
+ queryJobStates(query, flags, states);
+ return(states);
+}
+
+const std::list<JobStatus>
+ServerConnection::queryJobStatesList(const std::vector<QueryRecord>& query,
+ int flags) const
+{
+ std::vector<JobStatus> states;
+
+ queryJobStates(query, flags, states);
+ return std::list<JobStatus>(states.begin(),states.end());
+}
+
+
+void
+ServerConnection::queryJobStates(const std::vector<std::vector<QueryRecord> >& query,
+ int flags,
+ std::vector<JobStatus> & states) const
+{
+ edg_wll_QueryRec **cond = NULL;
+ edg_wll_JobStat *jobs, *j;
+ int result, qresults_param;
+ char *errstr = NULL;
+
+ try {
+ cond = convertQueryVectorExt(query);
+
+ result = edg_wll_QueryJobsExt(context, (const edg_wll_QueryRec**)cond,
+ flags, NULL, &jobs);
+ if (result == E2BIG) {
+ edg_wll_Error(context, NULL, &errstr);
+ check_result(edg_wll_GetParam(context,
+ EDG_WLL_PARAM_QUERY_RESULTS, &qresults_param),
+ context,
+ "edg_wll_GetParam(EDG_WLL_PARAM_QUERY_RESULTS)");
+ if (qresults_param != EDG_WLL_QUERYRES_LIMITED) {
+ edg_wll_SetError(context, result, errstr);
+ check_result(result, context,"edg_wll_QueryJobsExt");
+ }
+ } else {
+ check_result(result, context,"edg_wll_QueryJobsExt");
+ }
+
+ for(j = jobs; j->state != EDG_WLL_JOB_UNDEF; j++) {
+ edg_wll_JobStat *jsep = new edg_wll_JobStat;
+ if (jsep != NULL) {
+ memcpy(jsep, j, sizeof(*j));
+ states.push_back(JobStatus(*jsep));
+ }
+ }
+
+ if (result) {
+ edg_wll_SetError(context, result, errstr);
+ check_result(result, context,"edg_wll_QueryJobsExt");
+ }
+
+ delete jobs;
+
+ {
+ unsigned i;
+
+ for(i = 0; cond[i]; i++) {
+ freeQueryRecVector(cond[i]);
+ delete[] cond[i];
+ }
+ delete[] cond;
+ }
+
+
+ } catch (Exception &e) {
+ unsigned i;
+ if(cond) {
+ for(i = 0; cond[i]; i++) {
+ freeQueryRecVector(cond[i]);
+ delete[] cond[i];
+ }
+ delete[] cond;
+ }
+ if (errstr) free(errstr);
+
+ STACK_ADD;
+ throw;
+ }
+}
+
+
+const std::vector<JobStatus>
+ServerConnection::queryJobStates(const std::vector<std::vector<QueryRecord> >& query,
+ int flags) const
+{
+ std::vector<JobStatus> states;
+
+ queryJobStates(query, flags, states);
+ return(states);
+}
+
+
+void ServerConnection::userJobs(std::vector<edg::workload::common::jobid::JobId> & ids) const
+{
+ edg_wlc_JobId *jobs, *j;
+ int result, qresults_param;
+ char *errstr = NULL;
+
+ try {
+ result = edg_wll_UserJobs(context, &jobs, NULL);
+ if (result == E2BIG) {
+ edg_wll_Error(context, NULL, &errstr);
+ check_result(edg_wll_GetParam(context,
+ EDG_WLL_PARAM_QUERY_RESULTS, &qresults_param),
+ context,
+ "edg_wll_GetParam(EDG_WLL_PARAM_QUERY_RESULTS)");
+ if (qresults_param != EDG_WLL_QUERYRES_LIMITED) {
+ edg_wll_SetError(context, result, errstr);
+ check_result(result, context,"edg_wll_UserJobs");
+ }
+ } else {
+ check_result(result, context,"edg_wll_UserJobs");
+ }
+
+ for(j = jobs; *j; j++)
+ ids.push_back(edg::workload::common::jobid::JobId(*j));
+
+ if (result) {
+ edg_wll_SetError(context, result, errstr);
+ check_result(result, context,"edg_wll_QueryJobsExt");
+ }
+
+ free(jobs);
+
+ } catch (Exception &e) {
+ if (errstr) free(errstr);
+
+ STACK_ADD;
+ throw;
+ }
+}
+
+
+const std::vector<edg::workload::common::jobid::JobId>
+ServerConnection::userJobs() const
+{
+ std::vector<edg::workload::common::jobid::JobId> jobList;
+
+ userJobs(jobList);
+ return jobList;
+}
+
+
+void
+ServerConnection::userJobStates(std::vector<JobStatus> & states) const
+{
+ edg_wll_JobStat *jobs, *j;
+ int result, qresults_param;
+ char *errstr = NULL;
+
+ try {
+ result = edg_wll_UserJobs(context, NULL, &jobs);
+ if (result == E2BIG) {
+ edg_wll_Error(context, NULL, &errstr);
+ check_result(edg_wll_GetParam(context,
+ EDG_WLL_PARAM_QUERY_RESULTS, &qresults_param),
+ context,
+ "edg_wll_GetParam(EDG_WLL_PARAM_QUERY_RESULTS)");
+ if (qresults_param != EDG_WLL_QUERYRES_LIMITED) {
+ edg_wll_SetError(context, result, errstr);
+ check_result(result, context,"edg_wll_UserJobs");
+ }
+ } else {
+ check_result(result, context,"edg_wll_UserJobs");
+ }
+
+ for(j = jobs; j->state != EDG_WLL_JOB_UNDEF; j++) {
+ edg_wll_JobStat *jsep = new edg_wll_JobStat;
+ if (jsep != NULL) {
+ memcpy(jsep, j, sizeof(*j));
+ states.push_back(JobStatus(*jsep));
+ }
+ }
+
+ if (result) {
+ edg_wll_SetError(context, result, errstr);
+ check_result(result, context,"edg_wll_QueryJobsExt");
+ }
+
+ delete jobs;
+
+ } catch (Exception &e) {
+ if (errstr) free(errstr);
+
+ STACK_ADD;
+ throw;
+ }
+}
+
+
+const std::vector<JobStatus>
+ServerConnection::userJobStates() const
+{
+ std::vector<JobStatus> states;
+
+ userJobStates(states);
+ return(states);
+}
+
+
+edg_wll_Context
+ServerConnection::getContext(void) const
+{
+ return(context);
+}
+
+
+void ServerConnection::setParam(edg_wll_ContextParam par, int val)
+{
+ check_result(edg_wll_SetParamInt(context,par,val),
+ context,
+ "edg_wll_SetParamInt()");
+}
+
+void ServerConnection::setParam(edg_wll_ContextParam par, const std::string val)
+{
+ check_result(edg_wll_SetParamString(context,par,val.c_str()),
+ context,
+ "edg_wll_SetParamString()");
+}
+
+void ServerConnection::setParam(edg_wll_ContextParam par, const struct timeval & val)
+{
+ check_result(edg_wll_SetParamTime(context,par,&val),
+ context,
+ "edg_wll_SetParamTime()");
+}
+
+int ServerConnection::getParamInt(edg_wll_ContextParam par) const
+{
+ int ret;
+ check_result(edg_wll_GetParam(context,par,&ret),
+ context,
+ "edg_wll_GetParam()");
+ return ret;
+}
+
+std::string ServerConnection::getParamString(edg_wll_ContextParam par) const
+{
+ char *ret;
+ std::string out;
+
+ check_result(edg_wll_GetParam(context,par,&ret),
+ context,
+ "edg_wll_GetParam()");
+
+ out = ret;
+ free(ret);
+ return out;
+}
+
+struct timeval ServerConnection::getParamTime(edg_wll_ContextParam par) const
+{
+ struct timeval ret;
+ check_result(edg_wll_GetParam(context,par,&ret),
+ context,
+ "edg_wll_GetParam()");
+ return ret;
+}
+
+EWL_END_NAMESPACE;
--- /dev/null
+/*
+@@@AUTO
+*/
+
+@@@LANG: C
+
+#include "args.h"
+#include "glite/lb/events.h"
+
+#include <stdio.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/utsname.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+
+
+typedef struct {
+ int argc;
+ char** argv;
+ const char* help;
+ int idx;
+ edg_wll_Args list[1000];
+ int last;
+} opt_ctx_t;
+
+/* lists of accepted tags */
+@@@{
+ gen "static const char * const eventJobCommon\[] = {";
+ selectType $event '_common_';
+ for (getFieldsOrdered $event) {
+ my $f = selectField $event $_;
+ my $fn = $f->{name};
+ gen "\"$fn\", ";
+ }
+ gen "NULL };\n";
+@@@}
+@@@{
+ for my $t (sort { $event->{order}->{$a} <=> $event->{order}->{$b} }
+ $event->getTypes) {
+ gen "static const char * const event$t\[] = {";
+ selectType $event $t;
+ for (getFieldsOrdered $event) {
+ my $f = selectField $event $_;
+ my $fn = $f->{name};
+ gen "\"$fn\", "
+ }
+ gen "NULL };\n";
+ }
+@@@}
+
+static const char * const * const eventTags[] = {
+ eventJobCommon,
+@@@{
+ for my $t (sort { $event->{order}->{$a} <=> $event->{order}->{$b} }
+ $event->getTypes) {
+ gen "\tevent$t,\n";
+ }
+ gen "\tNULL\n};\n";
+@@@}
+
+static int read_bool(const edg_wll_Args* o, char* arg, char* par)
+{
+ int b = 1;
+ int rs = 0;
+
+ if (par)
+ {
+ if (!strcasecmp(par, "off") || !strcmp(par, "0")
+ || !strcasecmp(par, "false"))
+ {
+ b = 0;
+ rs = 1;
+ }
+ else if (!strcasecmp(par, "on") || !strcmp(par, "1")
+ || !strcasecmp(par, "true"))
+ {
+ rs = 1;
+ }
+ }
+
+ if (o->value)
+ *(int*)o->value = b;
+ return rs;
+}
+
+static void read_double(const edg_wll_Args* o, char* arg, char* par)
+{
+ double d;
+ if (!par)
+ {
+ printf("Option: %s - missing double/float value\n", arg);
+ exit(1);
+ }
+ d = atof(par);
+ if (o->min != o->max)
+ {
+ if (d < o->min && d > o->max)
+ {
+ printf("Option: %s - value: %f out of range <%d, %d>",
+ arg, d, o->min, o->max);
+ exit(1);
+ }
+ }
+ if (o->value)
+ *(double*)o->value = d;
+}
+
+static void read_string(const edg_wll_Args* o, char* arg, char* par)
+{
+ if (!par)
+ {
+ printf("Option: %s - missing string value\n", arg);
+ exit(1);
+ }
+ if (o->value)
+ {
+ if (strstr(arg, "-file"))
+ {
+ struct stat buf;
+ int fd = open(par, O_RDONLY);
+ if (fd >= 0)
+ {
+ char* b;
+ fstat(fd, &buf);
+ b = (char*) malloc(buf.st_size);
+ if (b)
+ {
+ int p = 0;
+ printf("Opened & reading %s %lld\n",
+ par, (long long)buf.st_size);
+ while (p < buf.st_size)
+ {
+ int r = read(fd, b + p, buf.st_size);
+ if (r < 0)
+ break;
+ p += r;
+ }
+
+ *(char**)o->value = b;
+ }
+ close(fd);
+ }
+ else
+ fprintf(stderr, "can't open file: \"%s\" (%s)\n", par, strerror(errno));
+
+ }
+ else
+ *(char**)o->value = strdup(par);
+ }
+}
+
+static void read_int(const edg_wll_Args* o, char* arg, char* par)
+{
+ int v = 0;
+ if (!par)
+ {
+ printf("Option: %s - missing integer value\n", arg);
+ exit(1);
+ }
+ sscanf(par, "%i", &v);
+ if (o->min != o->max)
+ {
+ if (v < o->min && v > o->max)
+ {
+ printf("Option: %s - value: %d out of range <%d, %d>",
+ arg, v, o->min, o->max);
+ exit(1);
+ }
+ }
+ if (o->value)
+ *(int*)o->value = v;
+}
+
+static void read_uint16(const edg_wll_Args* o, char* arg, char* par)
+{
+ int v = 0;
+ if (!par)
+ {
+ printf("Option: %s - missing integer value\n", arg);
+ exit(1);
+ }
+ sscanf(par, "%i", &v);
+ if (o->min != o->max)
+ {
+ if (v < o->min && v > o->max)
+ {
+ printf("Option: %s - value: %d out of range <%d, %d>",
+ arg, v, o->min, o->max);
+ exit(1);
+ }
+ }
+ if (o->value)
+ *(u_int16_t*)o->value = v;
+}
+
+static void read_event(const edg_wll_Args* o, char* arg, char* par)
+{
+ edg_wll_EventCode ec = edg_wll_StringToEvent(par);
+ if (ec == EDG_WLL_EVENT_UNDEF)
+ {
+ if (strcmp(par, "help") == 0)
+ {
+ // list type
+ int i;
+ printf("Available events: extra options\n");
+ for (i = EDG_WLL_EVENT_UNDEF + 1; i < EDG_WLL_EVENT__LAST; i++)
+ {
+ char* e = edg_wll_EventToString(i);
+ if (e)
+ {
+ int j = 0;
+ printf(" %s: ", e);
+ while (eventTags[i][j])
+ printf("%s ", eventTags[i][j++]);
+ fputc('\n', stdout);
+
+ free(e);
+ }
+ }
+ }
+ else
+ fprintf(stderr,"ERROR %s unknown event: %s\n", arg, par);
+ exit(1);
+ }
+ if (o->value)
+ *(edg_wll_EventCode*)o->value = ec;
+
+}
+
+static void read_source(const edg_wll_Args* o, char* arg, char* par)
+{
+ edg_wll_Source s = edg_wll_StringToSource(par);
+ if (s == EDG_WLL_SOURCE_NONE)
+ {
+ if (strcmp(par, "help") == 0)
+ {
+ // list type
+ int i;
+ printf("Valid sources:\n");
+ for (i = EDG_WLL_SOURCE_NONE + 1; i < EDG_WLL_SOURCE__LAST; i++)
+ {
+ char* e = edg_wll_SourceToString(i);
+ if (e)
+ {
+ printf(" %s\n", e);
+ free(e);
+ }
+ }
+ }
+ else
+ fprintf(stderr,"ERROR %s unknown source: %s\n", arg, par);
+ exit(1);
+ }
+ if (o->value)
+ *(edg_wll_Source*)o->value = s;
+}
+
+static void show_help(const edg_wll_Args* o, int prefix)
+{
+ unsigned max = 0;
+ char** l = malloc(sizeof(char*) * 1000);
+ int li = 0;
+ unsigned i = 0;
+
+ for (i = 0; o[i].type != EDG_WLL_ARGS_NONE; i++)
+ {
+ char b[80];
+ unsigned len;
+ if (o[i].type == EDG_WLL_ARGS_HELP)
+ sprintf(b, " -h --help");
+ else
+ sprintf(b, " %c%s %s%s",
+ (o[i].oshort && prefix) ? '-' : ' ',
+ o[i].oshort ? o[i].oshort : " ",
+ (o[i].olong && prefix) ? "--" : "",
+ o[i].olong ? o[i].olong : ""
+ //opt[i].options ? opt[i].options : "",
+ //o[i].help ? o[i].help : ""
+ );
+ l[li] = strdup(b);
+ li++;
+ len = strlen(b);
+ if (max < len)
+ max = len;
+ }
+ for (i = 0; o[i].type != EDG_WLL_ARGS_NONE; i++)
+ {
+ if (!o[i].oshort && !o[i].olong
+ && o[i].type != EDG_WLL_ARGS_HELP
+ && o[i].type != EDG_WLL_ARGS_OPTIONS)
+ continue;
+
+ if (o[i].type != EDG_WLL_ARGS_OPTIONS)
+ {
+ unsigned s;
+ fputs(l[i], stdout);
+ for (s = strlen(l[i]); s <= max; s++)
+ fputc(' ', stdout);
+ if (o[i].type == EDG_WLL_ARGS_HELP)
+ fputs("this help message", stdout);
+ }
+
+ if (o[i].value)
+ {
+ switch (o[i].type)
+ {
+ case EDG_WLL_ARGS_INT:
+ if (o[i].help)
+ printf(o[i].help, *(int*)o[i].value,
+ o[i].min, o[i].max);
+ break;
+ case EDG_WLL_ARGS_STRING:
+ case EDG_WLL_ARGS_SELECTSTRING:
+ if (o[i].help)
+ printf(o[i].help, *(const char**)o[i].value);
+ break;
+ case EDG_WLL_ARGS_OPTIONS:
+ show_help((const edg_wll_Args*)o[i].value, prefix);
+ continue;
+ default:
+ if (o[i].help)
+ fputs(o[i].help, stdout);
+ break;
+ }
+ }
+ else if (o[i].help)
+ fputs(o[i].help, stdout);
+
+ fputs("\n", stdout);
+ }
+ while (--li>=0) free(l[li]);
+ free(l);
+}
+#if 0
+static void parse_suboptions(const Option* o, const char* oname, char* pars, const char* r)
+{
+ avm::vector<char*> arr;
+ split(arr, pars);
+
+ if (!arr.size() || strcmp(arr[0], "help") == 0)
+ {
+ printf("Available options for '%s' (optA=x:optB=...)\n", oname);
+ show_help(o, false);
+ exit(0);
+ }
+ for (unsigned i = 0; i < arr.size(); i++)
+ {
+ char* par = strchr(arr[i], '=');
+ if (par)
+ {
+ *par = 0;
+ par++;
+ }
+
+ for (unsigned j = 0; o[j].type != Args::Option::NONE; j++)
+ {
+ if ((o[j].oshort && strcmp(o[j].oshort, arr[i]) == 0)
+ || (o[j].olong && strcmp(o[j].olong, arr[i]) == 0))
+ {
+ switch(o[j].type)
+ {
+ case Args::Option::BOOL:
+ read_bool(&o[j], arr[i], par, r);
+ break;
+ case Args::Option::DOUBLE:
+ read_double(&o[j], arr[i], par, r);
+ break;
+ case Args::Option::INT:
+ read_int(&o[j], arr[i], par, r);
+ break;
+ default:
+ ;
+ }
+ }
+ }
+ }
+}
+#endif
+
+static int findOpt(opt_ctx_t* ctx, int olong)
+{
+ char* arg = ctx->argv[ctx->idx] + olong + 1;
+ char* par = strchr(arg, '=');
+ const edg_wll_Args* o = NULL;
+ const edg_wll_Args* ol[200];
+ int olb = 0;
+ int ole = 0;
+
+ char* argnofile = strdup(arg);
+ char* nofile = strstr(argnofile, "-file"); // should be the ending
+ if (nofile && (nofile - argnofile) > 2)
+ nofile[0] = 0;
+
+ olong++;
+ if (par)
+ {
+ *par = 0;
+ par++;
+ }
+ else if ((ctx->idx + 1) < ctx->argc)
+ {
+ par = ctx->argv[++ctx->idx];
+ }
+
+ ol[ole++] = ctx->list;
+ while (ole > olb)
+ {
+ o = ol[olb++];
+ for (; o->type != EDG_WLL_ARGS_NONE; o++)
+ {
+ //printf("OPTION %d '%s' %d '%s' '%s'\n", o->type, arg, olong, o->oshort, o->olong);
+ if (o->type == EDG_WLL_ARGS_HELP
+ && (strcasecmp(arg, "h") == 0
+ || strcmp(arg, "?") == 0
+ || strcasecmp(arg, "help") == 0))
+ break;
+ if (o->type == EDG_WLL_ARGS_OPTIONS)
+ {
+ ol[ole++] = o->value;
+ continue;
+ }
+
+ if (olong < 2)
+ {
+ if (o->oshort &&
+ (strcmp(arg, o->oshort) == 0
+ || strcmp(argnofile, o->oshort) == 0))
+ break;
+ }
+ else if (o->olong && (strcmp(arg, o->olong) == 0
+ || strcmp(argnofile, o->olong) == 0))
+ break;
+ }
+ if (o->type != EDG_WLL_ARGS_NONE)
+ break;
+ }
+
+ switch (o->type)
+ {
+ case EDG_WLL_ARGS_NONE:
+ return -1;
+ case EDG_WLL_ARGS_BOOL:
+ if (!read_bool(o, arg, par))
+ ctx->idx--; // no argument given
+ break;
+ case EDG_WLL_ARGS_DOUBLE:
+ read_double(o, arg, par);
+ break;
+ case EDG_WLL_ARGS_STRING:
+ read_string(o, arg, par);
+ break;
+ case EDG_WLL_ARGS_INT:
+ read_int(o, arg, par);
+ break;
+ case EDG_WLL_ARGS_UINT16:
+ read_uint16(o, arg, par);
+ break;
+ case EDG_WLL_ARGS_EVENT:
+ read_event(o, arg, par);
+ break;
+ case EDG_WLL_ARGS_SOURCE:
+ read_source(o, arg, par);
+ break;
+ case EDG_WLL_ARGS_HELP:
+ printf("\nUsage: %s %s\n\n", ctx->argv[0], ctx->help);
+ show_help(ctx->list, 1);
+ exit(0);
+ //case EDG_WLL_ARGS_SUBOPTIONS:
+ //parse_suboptions((const edg_wll_Args*)o->value, arg, par, regname);
+ default:
+ printf("FIXME: unhandle option type %d\n", o->type);
+ break;
+ }
+
+ if (argnofile)
+ free(argnofile);
+
+ return 0;
+}
+
+static void addOptions(opt_ctx_t* ctx, const edg_wll_Args* options)
+{
+ const edg_wll_Args* o = options;
+
+ while (o->type != EDG_WLL_ARGS_NONE)
+ {
+ ctx->list[ctx->last++] = *o;
+ o++;
+ }
+}
+
+void edg_wll_ParseArgs(int* argc, char** argv, const edg_wll_Args* options,
+ const char* help)
+{
+ int sidx = 1;
+ opt_ctx_t ctx;
+
+ ctx.argc = *argc;
+ ctx.argv = argv;
+ ctx.help = help;
+ ctx.last = 0;
+
+ addOptions(&ctx, options);
+
+ for (ctx.idx = 1; ctx.idx < ctx.argc; ctx.idx++)
+ {
+ if (argv[ctx.idx][0] == '-')
+ {
+ int olong = (argv[ctx.idx][1] == '-');
+ if (olong && argv[ctx.idx][2] == 0)
+ break; // end of options
+ //printf("ARG %d %s\n", ctx.idx, argv[ctx.idx]);
+ if (findOpt(&ctx, olong) == 0)
+ continue;
+ }
+ else if (sidx != ctx.idx)
+ {
+ fprintf(stderr,"SIDX %d %d\n", sidx, ctx.idx);
+ argv[sidx] = argv[ctx.idx];
+ }
+ sidx++;
+ }
+
+ while (ctx.idx < *argc && sidx != ctx.idx)
+ {
+ argv[sidx++] = argv[ctx.idx++];
+ }
+
+ *argc = sidx;
+}
--- /dev/null
+#ifndef __EDG_WORKLOAD_LOGGING_CLIENT_ARGS_H__
+
+typedef enum {
+ EDG_WLL_ARGS_NONE = 0,
+ EDG_WLL_ARGS_BOOL,
+ EDG_WLL_ARGS_INT,
+ EDG_WLL_ARGS_UINT16,
+ EDG_WLL_ARGS_DOUBLE,
+ EDG_WLL_ARGS_STRING,
+ EDG_WLL_ARGS_HELP,
+ EDG_WLL_ARGS_JOBID,
+ EDG_WLL_ARGS_NOTIFID,
+ EDG_WLL_ARGS_SOURCE,
+ EDG_WLL_ARGS_EVENT,
+ EDG_WLL_ARGS_OPTIONS,
+ EDG_WLL_ARGS_SUBOPTIONS,
+ EDG_WLL_ARGS_SELECTSTRING,
+} edg_wll_ArgsCode;
+
+typedef struct {
+ edg_wll_ArgsCode type;
+ const char* oshort;
+ const char* olong;
+ const char* help;
+ void* value;
+ int min;
+ int max;
+} edg_wll_Args;
+
+void edg_wll_ParseArgs(int* argc, char** argv, const edg_wll_Args* parray,
+ const char* help);
+
+#endif /* __EDG_WORKLOAD_LOGGING_CLIENT_ARGS_H__ */
--- /dev/null
+#ident "$Header$"
+
+#include <errno.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <netinet/in.h>
+#include <netdb.h>
+
+#include "globus_config.h"
+#include "glite/wms/thirdparty/globus_ssl_utils/sslutils.h"
+
+#include "glite/lb/consumer.h"
+#include "glite/lb/context-int.h"
+#include "glite/lb/dgssl.h"
+#include "glite/lb/mini_http.h"
+
+
+
+static void CloseConnection(edg_wll_Context ctx, int conn_index)
+{
+ /* close connection ad free its structures */
+ if (ctx->connPool[conn_index].ssl)
+ edg_wll_ssl_close_timeout(ctx->connPool[conn_index].ssl,&ctx->p_tmp_timeout);
+ if (ctx->connPool[conn_index].gsiCred)
+ edg_wll_ssl_free(ctx->connPool[conn_index].gsiCred);
+ free(ctx->connPool[conn_index].peerName);
+ free(ctx->connPool[conn_index].buf);
+
+ memset(ctx->connPool + conn_index, 0, sizeof(edg_wll_ConnPool));
+
+ /* if deleted conn was not the last one -> there is a 'hole' and then */
+ /* 'shake' together connections in pool, no holes are allowed */
+ if (conn_index < ctx->connOpened - 1) {
+ ctx->connPool[conn_index] = ctx->connPool[ctx->connOpened - 1];
+ memset(ctx->connPool + ctx->connOpened - 1 , 0, sizeof(edg_wll_ConnPool));
+ }
+ ctx->connOpened--;
+}
+
+
+
+static int ConnectionIndex(edg_wll_Context ctx, const char *name, int port)
+{
+ int i;
+
+ for (i=0; i<ctx->connOpened;i++)
+ if (!strcmp(name, ctx->connPool[i].peerName) &&
+ (port == ctx->connPool[i].peerPort)) return i;
+
+ return -1;
+}
+
+
+
+static int AddConnection(edg_wll_Context ctx, char *name, int port)
+{
+ int index = ctx->connOpened;
+
+ free(ctx->connPool[index].peerName); // should be empty; just to be sure
+ ctx->connPool[index].peerName = strdup(ctx->srvName);
+ ctx->connPool[index].peerPort = ctx->srvPort;
+ ctx->connOpened++;
+
+ return index;
+}
+
+
+
+static void ReleaseConnection(edg_wll_Context ctx, char *name, int port)
+{
+ int i, index = 0;
+ long min;
+
+
+ if (ctx->connOpened == 0) return; /* nothing to release */
+
+ if (name) {
+ if ((index = ConnectionIndex(ctx, name, port)) >= 0)
+ CloseConnection(ctx, index);
+ }
+ else { /* free the oldest connection*/
+ min = ctx->connPool[0].lastUsed.tv_sec;
+ for (i=0; i<ctx->connOpened; i++) {
+ if (ctx->connPool[i].lastUsed.tv_sec < min) {
+ min = ctx->connPool[i].lastUsed.tv_sec;
+ index = i;
+ }
+ }
+ CloseConnection(ctx, index);
+ }
+}
+
+
+
+
+int edg_wll_close(edg_wll_Context ctx)
+{
+ edg_wll_ResetError(ctx);
+
+ CloseConnection(ctx, ctx->connToUse);
+
+ return edg_wll_Error(ctx,NULL,NULL);
+}
+
+
+
+int edg_wll_open(edg_wll_Context ctx)
+{
+ int index;
+
+
+ edg_wll_ResetError(ctx);
+
+ if ( (index = ConnectionIndex(ctx, ctx->srvName, ctx->srvPort)) == -1 ) {
+ /* no such open connection in pool */
+ if (ctx->connOpened == ctx->poolSize)
+ ReleaseConnection(ctx, NULL, 0);
+
+ index = AddConnection(ctx, ctx->srvName, ctx->srvPort);
+
+ }
+ /* else - there is cached open connection, reuse it */
+
+ ctx->connToUse = index;
+
+ if (!ctx->connPool[index].gsiCred) {
+ if (!(ctx->connPool[index].gsiCred = edg_wll_ssl_init(SSL_VERIFY_PEER,0,
+ ctx->p_proxy_filename ? ctx->p_proxy_filename : ctx->p_cert_filename,
+ ctx->p_proxy_filename ? ctx->p_proxy_filename : ctx->p_key_filename,
+ 0, 0)))
+ {
+ edg_wll_SetError(ctx,EDG_WLL_ERROR_SSL,
+ ERR_error_string(ERR_get_error(), NULL));
+ goto err;
+ }
+
+ }
+
+ if (!ctx->connPool[index].ssl) {
+ switch (edg_wll_ssl_connect(ctx->connPool[index].gsiCred,
+ ctx->connPool[index].peerName, ctx->connPool[index].peerPort,
+ &ctx->p_tmp_timeout,&ctx->connPool[index].ssl)) {
+
+ case EDG_WLL_SSL_OK:
+ goto ok;
+ case EDG_WLL_SSL_ERROR_ERRNO:
+ edg_wll_SetError(ctx,errno,"edg_wll_ssl_connect()");
+ break;
+ case EDG_WLL_SSL_ERROR_SSL:
+ edg_wll_SetError(ctx,EDG_WLL_ERROR_SSL,
+ ERR_error_string(ERR_get_error(), NULL));
+ break;
+ case EDG_WLL_SSL_ERROR_HERRNO:
+ { const char *msg1;
+ char *msg2;
+ msg1 = hstrerror(errno);
+ asprintf(&msg2, "edg_wll_ssl_connect(): %s", msg1);
+ edg_wll_SetError(ctx,EDG_WLL_ERROR_DNS, msg2);
+ free(msg2);
+ }
+ break;
+ case EDG_WLL_SSL_ERROR_EOF:
+ edg_wll_SetError(ctx,ECONNREFUSED,"edg_wll_ssl_connect():"
+ " server closed the connection, probably due to overload");
+ break;
+ case EDG_WLL_SSL_ERROR_TIMEOUT:
+ edg_wll_SetError(ctx,ETIMEDOUT,"edg_wll_ssl_connect()");
+ break;
+ }
+ }
+ else goto ok;
+
+err:
+ /* some error occured; close created connection
+ * and free all fields in connPool[index] */
+ CloseConnection(ctx, index);
+ok:
+ return edg_wll_Error(ctx,NULL,NULL);
+}
+
+
+
+/* transform HTTP error code to ours */
+int http_check_status(
+ edg_wll_Context ctx,
+ char *response)
+
+{
+ int code,len;
+
+ edg_wll_ResetError(ctx);
+ sscanf(response,"HTTP/%*f %n%d",&len,&code);
+ switch (code) {
+ case HTTP_OK:
+ break;
+ /* soft errors - some useful data may be returned too */
+ case HTTP_UNAUTH: /* EPERM */
+ case HTTP_NOTFOUND: /* ENOENT */
+ case HTTP_NOTIMPL: /* ENOSYS */
+ case HTTP_UNAVAIL: /* EAGAIN */
+ case HTTP_INVALID: /* EINVAL */
+ break;
+ case EDG_WLL_SSL_ERROR_HERRNO:
+ { const char *msg1;
+ char *msg2;
+ msg1 = hstrerror(errno);
+ asprintf(&msg2, "edg_wll_ssl_connect(): %s", msg1);
+ edg_wll_SetError(ctx,EDG_WLL_ERROR_DNS, msg2);
+ free(msg2);
+ }
+ break;
+ case HTTP_NOTALLOWED:
+ edg_wll_SetError(ctx, ENXIO, "Method Not Allowed");
+ break;
+ case HTTP_UNSUPPORTED:
+ edg_wll_SetError(ctx, ENOTSUP, "Protocol versions incompatible");
+ break;
+ case HTTP_INTERNAL:
+ /* fall through */
+ default:
+ edg_wll_SetError(ctx,EDG_WLL_ERROR_SERVER_RESPONSE,response+len);
+ }
+ return edg_wll_Error(ctx,NULL,NULL);
+}
+
+
+
+int edg_wll_http_send_recv(
+ edg_wll_Context ctx,
+ char *request,
+ const char * const *req_head,
+ char *req_body,
+ char **response,
+ char ***resp_head,
+ char **resp_body)
+{
+ if (edg_wll_open(ctx)) return edg_wll_Error(ctx,NULL,NULL);
+
+ switch (edg_wll_http_send(ctx,request,req_head,req_body)) {
+ case ENOTCONN:
+ edg_wll_close(ctx);
+ if (edg_wll_open(ctx)
+ || edg_wll_http_send(ctx,request,req_head,req_body))
+ return edg_wll_Error(ctx,NULL,NULL);
+ /* fallthrough */
+ case 0: break;
+ default: return edg_wll_Error(ctx,NULL,NULL);
+ }
+
+ if (edg_wll_http_recv(ctx,response,resp_head,resp_body) == ENOTCONN) {
+ edg_wll_close(ctx);
+ (void) (edg_wll_open(ctx)
+ || edg_wll_http_send(ctx,request,req_head,req_body)
+ || edg_wll_http_recv(ctx,response,resp_head,resp_body));
+ }
+
+ gettimeofday(&ctx->connPool[ctx->connToUse].lastUsed, NULL);
+
+ return edg_wll_Error(ctx,NULL,NULL);
+}
--- /dev/null
+#ifndef __EDG_WORKLOAD_LOGGING_CLIENT_CONNECTION_H__
+#define __EDG_WORKLOAD_LOGGING_CLIENT_CONNECTION_H__
+
+#ident "$Header"
+
+int edg_wll_close(edg_wll_Context ctx);
+int edg_wll_open(edg_wll_Context ctx);
+int edg_wll_http_send_recv(edg_wll_Context, char *, const char * const *, char *, char **, char ***, char **);
+int http_check_status(edg_wll_Context, char *);
+
+
+#endif /* __EDG_WORKLOAD_LOGGING_CLIENT_CONNECTION_H__ */
--- /dev/null
+#ident "$Header$"
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <errno.h>
+#include <string.h>
+#include <unistd.h>
+#include <assert.h>
+
+#include <expat.h>
+
+#include "globus_config.h"
+#include "glite/wms/thirdparty/globus_ssl_utils/sslutils.h"
+
+#include "glite/lb/consumer.h"
+#include "glite/lb/context-int.h"
+#include "glite/lb/mini_http.h"
+#include "glite/lb/xml_parse.h"
+#include "glite/lb/xml_conversions.h"
+
+#include "connection.h"
+
+static const char* const request_headers[] = {
+ "Cache-Control: no-cache",
+ "Accept: application/x-dglb",
+ "User-Agent: edg_wll_Api/" PROTO_VERSION "/" COMP_PROTO,
+ "Content-Type: application/x-dglb",
+ NULL
+};
+
+int set_server_name_and_port(edg_wll_Context, const edg_wll_QueryRec **);
+
+int edg_wll_QueryEventsExt(
+ edg_wll_Context ctx,
+ const edg_wll_QueryRec **job_conditions,
+ const edg_wll_QueryRec **event_conditions,
+ edg_wll_Event **eventsOut)
+{
+ int error = 0;
+ char *response = NULL,
+ *message = NULL,
+ *send_mess = NULL;
+
+ edg_wll_ResetError(ctx);
+
+ if ( edg_wll_QueryEventsRequestToXML(ctx, job_conditions, event_conditions, &send_mess) != 0 )
+ {
+ edg_wll_SetError(ctx , (edg_wll_ErrorCode) EINVAL, "Invalid query record.");
+ goto err;
+ }
+
+ if ((error = set_server_name_and_port(ctx,job_conditions)))
+ goto err; // XXX is it fatal??
+
+ ctx->p_tmp_timeout = ctx->p_query_timeout;
+ error = edg_wll_http_send_recv(ctx, "POST /queryEvents HTTP/1.1",request_headers,send_mess,
+ &response,NULL,&message);
+ if ( error != 0 )
+ goto err;
+
+ if (http_check_status(ctx,response))
+ goto err;
+
+ edg_wll_ParseQueryEvents(ctx,message,eventsOut);
+
+err:
+ free(response);
+ free(message);
+ free(send_mess);
+ return edg_wll_Error(ctx,NULL,NULL);
+}
+
+int edg_wll_QueryEvents(
+ edg_wll_Context ctx,
+ const edg_wll_QueryRec *job_conditions,
+ const edg_wll_QueryRec *event_conditions,
+ edg_wll_Event **eventsOut)
+{
+ edg_wll_QueryRec **jconds = NULL,
+ **econds = NULL;
+ int i,
+ njconds, neconds,
+ ret;
+
+ if ( job_conditions )
+ {
+ for ( njconds = 0; job_conditions[njconds].attr != EDG_WLL_QUERY_ATTR_UNDEF ; njconds++ )
+ ;
+ jconds = (edg_wll_QueryRec **) calloc(njconds+1, sizeof(edg_wll_QueryRec *));
+ for ( i = 0; i < njconds; i++ )
+ {
+ jconds[i] = (edg_wll_QueryRec *) calloc(2, sizeof(edg_wll_QueryRec));
+ jconds[i][0] = job_conditions[i];
+ }
+ }
+
+ if ( event_conditions )
+ {
+ for ( neconds = 0; event_conditions[neconds].attr != EDG_WLL_QUERY_ATTR_UNDEF ; neconds++ )
+ ;
+ econds = (edg_wll_QueryRec **) calloc(neconds+1, sizeof(edg_wll_QueryRec *));
+ for ( i = 0; i < neconds; i++ )
+ {
+ econds[i] = (edg_wll_QueryRec *) calloc(2, sizeof(edg_wll_QueryRec));
+ econds[i][0] = event_conditions[i];
+ }
+ }
+
+ if ( econds && jconds )
+ ret = edg_wll_QueryEventsExt(ctx, (const edg_wll_QueryRec **) jconds,
+ (const edg_wll_QueryRec **) econds, eventsOut);
+ if ( econds && !jconds )
+ ret = edg_wll_QueryEventsExt(ctx, NULL, (const edg_wll_QueryRec **) econds, eventsOut);
+ if ( !econds && jconds )
+ ret = edg_wll_QueryEventsExt(ctx, (const edg_wll_QueryRec **) jconds, NULL, eventsOut);
+ if ( !econds && !jconds )
+ ret = edg_wll_QueryEventsExt(ctx, NULL, NULL, eventsOut);
+
+ if ( jconds )
+ {
+ for ( i = 0; i < njconds ; i++ )
+ free(jconds[i]);
+ free(jconds);
+ }
+ if ( econds )
+ {
+ for ( i = 0; i < neconds ; i++ )
+ free(econds[i]);
+ free(econds);
+ }
+
+ return ret;
+}
+
+
+int edg_wll_QueryJobsExt(
+ edg_wll_Context ctx,
+ const edg_wll_QueryRec ** conditions,
+ int flags,
+ edg_wlc_JobId ** jobsOut,
+ edg_wll_JobStat ** statesOut)
+{
+ char *response = NULL, *message = NULL, *send_mess = NULL;
+
+ edg_wll_ResetError(ctx);
+
+ if (!jobsOut) flags |= EDG_WLL_STAT_NO_JOBS;
+ if (!statesOut) {flags = 0; flags |= EDG_WLL_STAT_NO_STATES;}
+ if (edg_wll_QueryJobsRequestToXML(ctx, conditions, flags, &send_mess) != 0) {
+ edg_wll_SetError(ctx , (edg_wll_ErrorCode) EINVAL, "Invalid query record.");
+ goto err;
+ }
+
+ if (set_server_name_and_port(ctx, conditions))
+ goto err;
+
+ ctx->p_tmp_timeout = ctx->p_query_timeout;
+
+ if (edg_wll_http_send_recv(ctx, "POST /queryJobs HTTP/1.1",request_headers,send_mess,
+ &response,NULL,&message))
+ goto err;
+
+ if (http_check_status(ctx,response))
+ goto err;
+
+ edg_wll_ParseQueryJobs(ctx,message,jobsOut,statesOut);
+
+err:
+ free(response);
+ free(message);
+ free(send_mess);
+
+ return edg_wll_Error(ctx,NULL,NULL);
+}
+
+int edg_wll_QueryJobs(
+ edg_wll_Context ctx,
+ const edg_wll_QueryRec * conditions,
+ int flags,
+ edg_wlc_JobId ** jobsOut,
+ edg_wll_JobStat ** statesOut)
+{
+ edg_wll_QueryRec **conds;
+ int i, nconds, ret;
+
+ if ( !conditions )
+ return edg_wll_QueryJobsExt(ctx, NULL, flags, jobsOut, statesOut);
+
+ for ( nconds = 0; conditions[nconds].attr != EDG_WLL_QUERY_ATTR_UNDEF ; nconds++ )
+ ;
+ conds = (edg_wll_QueryRec **) malloc((nconds+1) * sizeof(edg_wll_QueryRec *));
+ conds[nconds] = NULL;
+ for ( i = 0; i < nconds ; i++ )
+ {
+ conds[i] = (edg_wll_QueryRec *) malloc(2 * sizeof(edg_wll_QueryRec));
+ conds[i][0] = conditions[i];
+ conds[i][1].attr = EDG_WLL_QUERY_ATTR_UNDEF;
+ }
+
+ ret = edg_wll_QueryJobsExt(ctx, (const edg_wll_QueryRec **) conds, flags, jobsOut, statesOut);
+
+ for ( i = 0; i < nconds ; i++ )
+ free(conds[i]);
+ free(conds);
+
+
+ return ret;
+}
+
+
+
+int edg_wll_GetIndexedAttrs(
+ edg_wll_Context ctx,
+ edg_wll_QueryRec ***attrs)
+{
+ char *response = NULL, *send_mess = NULL, *message = NULL;
+
+ edg_wll_ResetError(ctx);
+
+ edg_wll_IndexedAttrsRequestToXML(ctx, &send_mess);
+
+ if (set_server_name_and_port(ctx, NULL))
+ goto err;
+
+ ctx->p_tmp_timeout = ctx->p_query_timeout;
+
+ if (edg_wll_http_send_recv(ctx, "POST /indexedAttrs HTTP/1.1",request_headers, send_mess,
+ &response,NULL,&message))
+ goto err;
+
+ if (http_check_status(ctx,response))
+ goto err;
+
+ edg_wll_ParseIndexedAttrs(ctx,message,attrs);
+
+err:
+ free(response);
+ free(message);
+
+ return edg_wll_Error(ctx,NULL,NULL);
+}
+
+
+/*
+ * wrappers around edg_wll_Query()
+ */
+
+int edg_wll_UserJobs(
+ edg_wll_Context ctx,
+ edg_wlc_JobId **jobsOut,
+ edg_wll_JobStat **statesOut)
+{
+ edg_wll_QueryRec j[2];
+
+ memset(j,0,sizeof j);
+
+ j[0].attr = EDG_WLL_QUERY_ATTR_OWNER;
+ j[0].op = EDG_WLL_QUERY_OP_EQUAL;
+ j[0].value.c = ctx->peerName;
+
+ return edg_wll_QueryJobs(ctx,j,0,jobsOut,statesOut);
+}
+
+int edg_wll_JobLog(
+ edg_wll_Context ctx,
+ edg_wlc_JobId job,
+ edg_wll_Event **eventsOut)
+{
+ edg_wll_QueryRec j[2], e[2];
+
+ memset(j,0,sizeof j);
+ memset(e,0,sizeof e);
+
+ j[0].attr = EDG_WLL_QUERY_ATTR_JOBID;
+ j[0].op = EDG_WLL_QUERY_OP_EQUAL;
+ j[0].value.j = job;
+
+ e[0].attr = EDG_WLL_QUERY_ATTR_LEVEL;
+ e[0].op = EDG_WLL_QUERY_OP_LESS;
+ e[0].value.i = ctx->p_level + 1;
+
+ return edg_wll_QueryEvents(ctx,j,e,eventsOut);
+}
+
+int edg_wll_JobStatus(
+ edg_wll_Context ctx,
+ edg_wlc_JobId job,
+ int flags,
+ edg_wll_JobStat *stat)
+{
+ edg_wll_QueryRec j[2];
+ edg_wll_JobStat *statesOut = NULL;
+ int ret;
+
+ memset(j,0,sizeof j);
+
+ j[0].attr = EDG_WLL_QUERY_ATTR_JOBID;
+ j[0].op = EDG_WLL_QUERY_OP_EQUAL;
+ j[0].value.j = job;
+ j[1].attr = EDG_WLL_QUERY_ATTR_UNDEF;
+
+ ret = edg_wll_QueryJobs(ctx,j,flags,NULL,&statesOut);
+
+ if (ret) return ret;
+
+ if (statesOut) {
+ if (statesOut[0].state == EDG_WLL_JOB_UNDEF) {
+ memcpy(stat, statesOut, sizeof(edg_wll_JobStat));
+ free(statesOut);
+ ret = edg_wll_SetError(ctx , (edg_wll_ErrorCode) ENOENT, "Query returned no result.");
+ }
+ else {
+ /* check wheter there is only one field in status reply */
+ assert(statesOut[1].state == EDG_WLL_JOB_UNDEF);
+ /* copy only 1st status */
+ memcpy(stat, statesOut, sizeof(edg_wll_JobStat));
+ /* release only array of states, keep all links unfreed for the previous copy */
+ free(statesOut);
+ }
+ }
+
+ return ret;
+}
+
+
+
+int edg_wll_QueryListener(edg_wll_Context ctx, edg_wlc_JobId job, const char *name, char** host, uint16_t *port) {
+
+ int i;
+ edg_wll_Event *events = NULL;
+ int errCode = 0;
+ edg_wll_QueryRec jr[2],er[2];
+ int found = 0;
+
+ memset(jr,0,sizeof jr);
+ memset(er,0,sizeof er);
+ jr[0].attr = EDG_WLL_QUERY_ATTR_JOBID;
+ jr[0].op = EDG_WLL_QUERY_OP_EQUAL;
+ jr[0].value.j = job;
+
+ er[0].attr = EDG_WLL_QUERY_ATTR_EVENT_TYPE;
+ er[0].op = EDG_WLL_QUERY_OP_EQUAL;
+ er[0].value.i = EDG_WLL_EVENT_LISTENER;
+
+ if (edg_wll_QueryEvents(ctx, jr, er, &events)) {
+ return edg_wll_Error(ctx, NULL, NULL);
+ }
+
+ for (i=0; events[i].type != EDG_WLL_EVENT_UNDEF; i++) {
+ if (!strcmp(name, events[i].listener.svc_name)) {
+ found = 1;
+ if (host != NULL)
+ *host = strdup(events[i].listener.svc_host);
+ if (port != NULL)
+ *port = events[i].listener.svc_port;
+ }
+ edg_wll_FreeEvent(&events[i]);
+ }
+ free(events);
+
+ if (!found)
+ errCode = ENOENT;
+
+ return edg_wll_SetError(ctx, errCode, NULL);
+}
+
+
+
+int set_server_name_and_port(edg_wll_Context ctx, const edg_wll_QueryRec **job_conditions)
+{
+ int i = 0, j,
+ found = 0,
+ error = 0;
+ int srvPort = 0,
+ srvPortTmp;
+ char *srvName = NULL,
+ *srvNameTmp;
+
+
+ if ( job_conditions ) for ( j = 0; job_conditions[j]; j++ )
+ for ( i = 0; (job_conditions[j][i].attr != EDG_WLL_QUERY_ATTR_UNDEF); i++ )
+ if ( job_conditions[j][i].attr == EDG_WLL_QUERY_ATTR_JOBID)
+ {
+ edg_wlc_JobIdGetServerParts(job_conditions[j][i].value.j,&srvNameTmp,&srvPortTmp);
+ if ( found )
+ {
+ if ( strcmp(srvName, srvNameTmp) || (srvPort != srvPortTmp) )
+ {
+ free(srvNameTmp); free(srvName);
+ return edg_wll_SetError(ctx, EINVAL, "Two different servers specifieed in one query");
+ }
+ free(srvNameTmp);
+ }
+ else
+ {
+ srvName = srvNameTmp;
+ srvPort = srvPortTmp;
+ found = 1;
+ }
+ }
+
+ if ( found && !ctx->p_query_server_override)
+ {
+ if (!ctx->srvName)
+ {
+ ctx->srvName = strdup(srvName);
+ ctx->srvPort = srvPort;
+ free(srvName);
+ }
+ else if (strcmp(srvName, ctx->srvName) || (srvPort != ctx->srvPort))
+ {
+ free(ctx->srvName);
+ ctx->srvName = strdup(srvName);
+ ctx->srvPort = srvPort;
+ free(srvName);
+ }
+ }
+ else if ( !ctx->srvName || !ctx->srvPort )
+ {
+ if (!ctx->p_query_server)
+ return(edg_wll_SetError(ctx, (edg_wll_ErrorCode) EINVAL, "Hostname of server to query is not set"));
+ else ctx->srvName = strdup(ctx->p_query_server);
+ if (!ctx->p_query_server_port)
+ return(edg_wll_SetError(ctx, (edg_wll_ErrorCode) EINVAL, "Port of server to query is not set"));
+ else ctx->srvPort = ctx->p_query_server_port;
+ }
+
+ return(error);
+}
--- /dev/null
+#ident "$Header$"
+
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <getopt.h>
+#include <string.h>
+#include <time.h>
+#include <errno.h>
+
+#include <globus_common.h>
+
+#define CLIENT_SBIN_PROG
+
+#include "glite/lb/consumer.h"
+#include "glite/lb/context-int.h"
+#include "glite/lb/dump.h"
+#include "glite/lb/ulm_parse.h"
+#include "glite/lb/xml_parse.h"
+#include "glite/lb/mini_http.h"
+#include "glite/wms/tls/ssl_helpers/ssl_inits.h"
+
+
+#define dprintf(x) { if (debug) printf x; }
+
+static const char rcsid[] = "@(#)$Id$";
+
+static int debug=0;
+
+static void printerr(edg_wll_Context ctx);
+
+static struct option opts[] = {
+ { "from", required_argument, NULL, 'f'},
+ { "to", required_argument, NULL, 't'},
+ { "help", no_argument, NULL, 'h' },
+ { "version", no_argument, NULL, 'v' },
+ { "debug", no_argument, NULL, 'd' },
+ { "server", required_argument, NULL, 'm' },
+ { NULL, no_argument, NULL, 0 }
+};
+
+static void usage(char *me)
+{
+ fprintf(stderr,"usage: %s [option]\n"
+ " -f, --from YYYYMMDDHHmmss beginning of the time interval for events to be dumped\n"
+ " -t, --to YYYYMMDDHHmmss end of the time interval for events to be dumped\n"
+ " -h, --help display this help\n"
+ " -v, --version display version\n"
+ " -d, --debug diagnostic output\n"
+ " -m, --server L&B server machine name\n",
+ me);
+}
+
+int main(int argc,char *argv[])
+{
+ edg_wll_DumpRequest *request;
+ edg_wll_DumpResult *result;
+ char *server = NULL;
+ char date[ULM_DATE_STRING_LENGTH+1];
+
+ char *me;
+ int opt;
+ edg_wll_Context ctx;
+
+ /* initialize request to server defaults */
+ request = (edg_wll_DumpRequest *) calloc(1,sizeof(edg_wll_DumpRequest));
+ request->from = EDG_WLL_DUMP_LAST_END;
+ request->to = EDG_WLL_DUMP_NOW;
+
+ /* initialize result */
+ result = (edg_wll_DumpResult *) calloc(1,sizeof(edg_wll_DumpResult));
+
+ me = strrchr(argv[0],'/');
+ if (me) me++; else me=argv[0];
+
+ /* get arguments */
+ while ((opt = getopt_long(argc,argv,"f:t:m:dvh",opts,NULL)) != EOF) {
+
+ switch (opt) {
+
+ case 'f': request->from = (time_t) edg_wll_ULMDateToDouble(optarg); break;
+ case 't': request->to = (time_t) edg_wll_ULMDateToDouble(optarg); break;
+ case 'm': server = optarg; break;
+ case 'd': debug = 1; break;
+ case 'v': fprintf(stdout,"%s:\t%s\n",me,rcsid); exit(0);
+ case 'h':
+ case '?': usage(me); return 1;
+ }
+ }
+
+ /* Initialize Globus common module */
+ dprintf(("Initializing Globus common module..."));
+ if (globus_module_activate(GLOBUS_COMMON_MODULE) != GLOBUS_SUCCESS) {
+ dprintf(("no.\n"));
+ fprintf(stderr,"Unable to initialize Globus common module\n");
+ } else {
+ dprintf(("yes.\n"));
+ }
+
+ edg_wlc_SSLInitialization();
+
+ /* check request */
+ if (debug) {
+ printf("Dump request:\n");
+ if (request->from < 0) {
+ printf("- from: %ld.\n",request->from);
+ } else {
+ if (edg_wll_ULMTimevalToDate(request->from,0,date) != 0) {
+ fprintf(stderr,"Error parsing 'from' argument.\n");
+ goto main_end;
+ }
+ printf("- from: %ld (i.e. %s).\n",request->from,date);
+ }
+ if (request->to < 0) {
+ printf("- to: %ld.\n",request->to);
+ } else {
+ if (edg_wll_ULMTimevalToDate(request->to,0,date) != 0) {
+ fprintf(stderr,"Error parsing 'to' argument.\n");
+ goto main_end;
+ }
+ printf("- to: %ld (i.e. %s).\n",request->to,date);
+ }
+ }
+
+ /* initialize context */
+ edg_wll_InitContext(&ctx);
+ if ( server )
+ {
+ char *p = strchr(server, ':');
+ if ( p )
+ {
+ edg_wll_SetParam(ctx, EDG_WLL_PARAM_QUERY_SERVER_PORT, atoi(p+1));
+ *p = 0;
+ }
+ edg_wll_SetParam(ctx, EDG_WLL_PARAM_QUERY_SERVER, server);
+ }
+
+ /* that is the DumpEvents */
+ dprintf(("Running the edg_wll_DumpEvents...\n"));
+ if (edg_wll_DumpEvents(ctx, request, result) != 0) {
+ fprintf(stderr,"Error running the edg_wll_DumpEvents().\n");
+ printerr(ctx);
+ switch ( edg_wll_Error(ctx, NULL, NULL) )
+ {
+ case ENOENT:
+ case EPERM:
+ case EINVAL:
+ break;
+ default:
+ goto main_end;
+ }
+ }
+
+ /* examine the result */
+ dprintf(("Examining the result of edg_wll_DumpEvents...\n"));
+ printf("Dump result:\n");
+ if (result->server_file) {
+ printf("- The jobs were dumped to the file '%s' at the server.\n",result->server_file);
+ } else {
+ printf("- The jobs were not dumped.\n");
+ }
+ if (edg_wll_ULMTimevalToDate(result->from,0,date) != 0) {
+ fprintf(stderr,"Error parsing 'from' argument.\n");
+ goto main_end;
+ }
+ printf("- from: %ld (i.e. %s).\n",result->from,date);
+ if (edg_wll_ULMTimevalToDate(result->to,0,date) != 0) {
+ fprintf(stderr,"Error parsing 'to' argument.\n");
+ goto main_end;
+ }
+ printf("- to: %ld (i.e. %s).\n",result->to,date);
+
+main_end:
+ dprintf(("End.\n"));
+ if (request) free(request);
+ if (result) free(result);
+ edg_wll_FreeContext(ctx);
+ return 0;
+}
+
+
+static void printerr(edg_wll_Context ctx)
+{
+ char *errt,*errd;
+
+ edg_wll_Error(ctx,&errt,&errd);
+ fprintf(stderr,"%s (%s)\n",errt,errd);
+}
+
+
+static const char* const request_headers[] = {
+ "Cache-Control: no-cache",
+ "Accept: application/x-dglb",
+ "User-Agent: edg_wll_Api/" PROTO_VERSION "/" COMP_PROTO,
+ "Content-Type: application/x-dglb",
+ NULL
+};
+
+int edg_wll_DumpEvents(
+ edg_wll_Context ctx,
+ const edg_wll_DumpRequest *request,
+ edg_wll_DumpResult *result)
+{
+ int error;
+ char *send_mess,
+ *response = NULL,
+ *recv_mess = NULL;
+
+ edg_wll_DumpRequestToXML(ctx, request, &send_mess);
+
+ //edg_wll_SetParam(ctx, EDG_WLL_PARAM_QUERY_TIMEOUT, 4000);
+ ctx->p_tmp_timeout.tv_sec = 400;
+
+ if (set_server_name_and_port(ctx, NULL))
+ goto edg_wll_dumpevents_end;
+
+ error = edg_wll_http_send_recv(ctx,
+ "POST /dumpRequest HTTP/1.1", request_headers, send_mess,
+ &response, NULL, &recv_mess);
+ if ( error != 0 )
+ goto edg_wll_dumpevents_end;
+
+ if (http_check_status(ctx, response, &recv_mess))
+ goto edg_wll_dumpevents_end;
+
+ edg_wll_ParseDumpResult(ctx, recv_mess, result);
+
+edg_wll_dumpevents_end:
+ if (response) free(response);
+ if (recv_mess) free(recv_mess);
+ if (send_mess) free(send_mess);
+ return edg_wll_Error(ctx,NULL,NULL);
+}
--- /dev/null
+#ident "$Header$"
+
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <getopt.h>
+#include <string.h>
+#include <time.h>
+#include <errno.h>
+
+#include <globus_common.h>
+
+#define CLIENT_SBIN_PROG
+
+#include "glite/lb/consumer.h"
+#include "glite/lb/context-int.h"
+#include "glite/lb/load.h"
+#include "glite/lb/ulm_parse.h"
+#include "glite/lb/xml_parse.h"
+#include "glite/lb/mini_http.h"
+#include "glite/wms/tls/ssl_helpers/ssl_inits.h"
+
+#define dprintf(x) { if (debug) printf x; }
+
+static const char rcsid[] = "@(#)$Id$";
+
+static int debug=0;
+
+static void printerr(edg_wll_Context ctx);
+
+static struct option opts[] = {
+ { "file", required_argument, NULL, 'f'},
+ { "help", no_argument, NULL, 'h' },
+ { "version", no_argument, NULL, 'v' },
+ { "debug", no_argument, NULL, 'd' },
+ { "server", required_argument, NULL, 'm' },
+ { NULL, no_argument, NULL, 0 }
+};
+
+static void usage(char *me)
+{
+ fprintf(stderr,"usage: %s [option]\n"
+ " -m, --server L&B server machine name\n"
+ " -f, --file filename file with dumped data to be loaded\n"
+ " -h, --help display this help\n"
+ " -v, --version display version\n"
+ " -d, --debug diagnostic output\n",
+ me);
+}
+
+int main(int argc,char *argv[])
+{
+ edg_wll_LoadRequest *request;
+ edg_wll_LoadResult *result;
+ char *server = NULL;
+ char date[ULM_DATE_STRING_LENGTH+1];
+
+ char *me;
+ int opt;
+ edg_wll_Context ctx;
+
+ /* initialize request to server defaults */
+ request = (edg_wll_LoadRequest *) calloc(1,sizeof(edg_wll_LoadRequest));
+ request->server_file = NULL;
+
+ /* initialize result */
+ result = (edg_wll_LoadResult *) calloc(1,sizeof(edg_wll_LoadResult));
+
+ me = strrchr(argv[0],'/');
+ if (me) me++; else me=argv[0];
+
+ /* get arguments */
+ while ((opt = getopt_long(argc,argv,"f:t:m:dvh",opts,NULL)) != EOF) {
+
+ switch (opt) {
+
+ case 'f': request->server_file = optarg; break;
+ case 'm': server = optarg; break;
+ case 'd': debug = 1; break;
+ case 'v': fprintf(stdout,"%s:\t%s\n",me,rcsid); exit(0);
+ case 'h':
+ case '?': usage(me); return 1;
+ }
+ }
+
+ /* Initialize Globus common module */
+ dprintf(("Initializing Globus common module..."));
+ if (globus_module_activate(GLOBUS_COMMON_MODULE) != GLOBUS_SUCCESS) {
+ dprintf(("no.\n"));
+ fprintf(stderr,"Unable to initialize Globus common module\n");
+ } else {
+ dprintf(("yes.\n"));
+ }
+
+ edg_wlc_SSLInitialization();
+
+ /* initialize context */
+ edg_wll_InitContext(&ctx);
+ if ( server )
+ {
+ char *p = strchr(server, ':');
+ if ( p )
+ {
+ edg_wll_SetParam(ctx, EDG_WLL_PARAM_QUERY_SERVER_PORT, atoi(p+1));
+ *p = 0;
+ }
+ edg_wll_SetParam(ctx, EDG_WLL_PARAM_QUERY_SERVER, server);
+ }
+
+ /* check request */
+ if (debug) {
+ printf("Load request:\n");
+ if (request->server_file) {
+ printf("- server_file: %s.\n",request->server_file);
+ } else {
+ printf("- server_file: not specified.\n");
+ }
+ }
+
+ /* that is the LoadEvents */
+ dprintf(("Running the edg_wll_LoadEvents...\n"));
+ if (edg_wll_LoadEvents(ctx, request, result) != 0) {
+ fprintf(stderr,"Error running the edg_wll_LoadEvents().\n");
+ printerr(ctx);
+ if ( !result->server_file )
+ goto main_end;
+ }
+
+ /* examine the result */
+ dprintf(("Examining the result of edg_wll_LoadEvents...\n"));
+ printf("Load result:\n");
+ if (result->server_file)
+ printf("- Unloaded events were stored into the server file '%s'.\n", result->server_file);
+ if (edg_wll_ULMTimevalToDate(result->from,0,date) != 0) {
+ fprintf(stderr,"Error parsing 'from' argument.\n");
+ goto main_end;
+ }
+ printf("- from: %ld (i.e. %s).\n",result->from,date);
+ if (edg_wll_ULMTimevalToDate(result->to,0,date) != 0) {
+ fprintf(stderr,"Error parsing 'to' argument.\n");
+ goto main_end;
+ }
+ printf("- to: %ld (i.e. %s).\n",result->to,date);
+
+main_end:
+ dprintf(("End.\n"));
+ if (request) free(request);
+ if (result)
+ {
+ if (result->server_file)
+ free(result->server_file);
+ free(result);
+ }
+ edg_wll_FreeContext(ctx);
+ return 0;
+}
+
+
+static void printerr(edg_wll_Context ctx)
+{
+ char *errt,*errd;
+
+ edg_wll_Error(ctx,&errt,&errd);
+ fprintf(stderr,"%s (%s)\n",errt,errd);
+}
+
+
+static const char* const request_headers[] = {
+ "Cache-Control: no-cache",
+ "Accept: application/x-dglb",
+ "User-Agent: edg_wll_Api/" PROTO_VERSION "/" COMP_PROTO,
+ "Content-Type: application/x-dglb",
+ NULL
+};
+
+int edg_wll_LoadEvents(
+ edg_wll_Context ctx,
+ const edg_wll_LoadRequest *request,
+ edg_wll_LoadResult *result)
+{
+ int error;
+ char *send_mess,
+ *response = NULL,
+ *recv_mess = NULL;
+
+ edg_wll_LoadRequestToXML(ctx, request, &send_mess);
+
+ //edg_wll_SetParam(ctx, EDG_WLL_PARAM_QUERY_TIMEOUT, 4000);
+ ctx->p_tmp_timeout.tv_sec = 400;
+
+ if (set_server_name_and_port(ctx, NULL))
+ goto edg_wll_loadevents_end;
+
+ error = edg_wll_http_send_recv(ctx,
+ "POST /loadRequest HTTP/1.1", request_headers, send_mess,
+ &response, NULL, &recv_mess);
+ if ( error != 0 )
+ goto edg_wll_loadevents_end;
+
+ if (http_check_status(ctx, response, &recv_mess))
+ goto edg_wll_loadevents_end;
+
+ edg_wll_ParseLoadResult(ctx, recv_mess, result);
+
+edg_wll_loadevents_end:
+ if (response) free(response);
+ if (recv_mess) free(recv_mess);
+ if (send_mess) free(send_mess);
+ return edg_wll_Error(ctx,NULL,NULL);
+}
--- /dev/null
+/*
+@@@AUTO
+*/
+
+@@@LANG: C
+
+#ident "$Header$"
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <errno.h>
+#include <math.h> // log
+#include <ctype.h> // isspace
+
+#include <globus_common.h>
+
+#include "glite/wms/jobid/cjobid.h"
+#include "glite/lb/notifid.h"
+#include "glite/lb/producer.h"
+#include "glite/lb/events.h"
+#include "glite/wms/tls/ssl_helpers/ssl_inits.h"
+
+#include "args.h"
+
+ //" %s -p -l 100000 -j https://localhost/First_JobIV?localhost:7771 -s UserInterface -e jobAbort DG.JOB.ABORT.REASON=\"oops\"\n\n",
+
+// undefine to disable support for -l option
+#define ENABLE_REASON_LENGTH
+
+int main(int argc, char *argv[])
+{
+ char /* *fmt,*fname = NULL,*/ *fmt_arg=NULL;
+ char* server = NULL,*code = NULL;
+ char* ff = NULL,*jobid_s = NULL;
+ char *src_instance = NULL;
+ int err = 0/*,i,done = 0,fmtlen*/;
+ int pri = 0;
+ int deb = 0;
+#ifdef ENABLE_REASON_LENGTH
+ int elength = 0;
+#endif
+ edg_wll_Context ctx;
+ edg_wll_Source src;
+ edg_wll_EventCode event = EDG_WLL_EVENT_UNDEF;
+ edg_wlc_JobId jobid = 0;
+ int (*logev)(edg_wll_Context context,
+ edg_wll_EventCode event,
+ char *fmt, ...);
+
+@@@{
+ my %vars = ();
+ for my $t (sort { $event->{order}->{$a} <=> $event->{order}->{$b} }
+ $event->getTypes) {
+ selectType $event $t;
+ for ($event->getFieldsOrdered) {
+ my $f = selectField $event $_;
+ my $fn = $f->getName;
+ my $type = {
+ "type" => $f->getType,
+ "defval" => $f->getDefaultNullValue
+ };
+
+ $type = { type=>'char *',defval=>'NULL' } if $f->{codes};
+
+ $vars{$fn} = $type;
+ }
+ }
+ foreach $name ( sort keys %vars ) {
+ gen qq{\t$vars{$name}->{"type"} $name = $vars{$name}->{"defval"};\n};
+ }
+@@@}
+
+ edg_wll_Args parray[] = {
+ { EDG_WLL_ARGS_EVENT, "e", "event", "select event type (see -e help)", &event },
+ { EDG_WLL_ARGS_BOOL, "p", "priority", "send as priority event", &pri },
+ { EDG_WLL_ARGS_STRING, "m", "machine", 0, &server },
+ { EDG_WLL_ARGS_SOURCE, "s", "source", "event source (see -s help)", &src },
+ { EDG_WLL_ARGS_STRING, "i", "source-instance", "event source instance", &src_instance },
+ { EDG_WLL_ARGS_STRING, "j", "jobid", "JobId", &jobid_s },
+ { EDG_WLL_ARGS_STRING, "c", "sequence", "event sequence code", &code },
+ { EDG_WLL_ARGS_BOOL, "d", "debug mode", "enable debug mode", &deb },
+#ifdef ENABLE_REASON_LENGTH
+ { EDG_WLL_ARGS_INT, "l", "reason-length", "extend 'reason' string to length (debug only)", &elength, 0, 1000000000 },
+#endif
+@@@{
+ my %typetab = (
+ "char *", "EDG_WLL_ARGS_STRING",
+ "int", "EDG_WLL_ARGS_INT",
+ "edg_wlc_JobId", "EDG_WLL_ARGS_JOBID",
+ "edg_wll_NotifId", "EDG_WLL_ARGS_NOTIFID",
+ "edg_wll_Source", "EDG_WLL_ARGS_SOURCE",
+ "uint16_t", "EDG_WLL_ARGS_UINT16"
+ );
+ my %vars = ();
+ for my $t (sort { $event->{order}->{$a} <=> $event->{order}->{$b} }
+ $event->getTypes) {
+ selectType $event $t;
+ for ($event->getFieldsOrdered) {
+ my $f = selectField $event $_;
+ my $ft = $f->{codes} ? 'char *' : $f->getType;
+ my $fn = $f->getName;
+ my $fc = $f->getComment;
+ $namehelp = { "type" => $ft, "help" => $fc };
+# gen qq{ $fn $ft $fc \n};
+ $vars{$fn} = $namehelp;
+ }
+ }
+ foreach $name ( sort keys %vars ) {
+# gen qq{ $vars{$name} $name \n };
+ gen qq{\t \{ $typetab{$vars{$name}->{"type"}}, 0, "$name", "$vars{$name}->{"help"}", &$name \},\n};
+ }
+
+@@@}
+ { EDG_WLL_ARGS_HELP },
+ { EDG_WLL_ARGS_NONE },
+ };
+ edg_wll_ParseArgs(&argc, argv, parray,
+ "Usage: %s [-d] [-p] [-l eventlen] [-j dg_jobid]"
+ "[-s source_id] -e event [key=value ...]");
+
+ if (globus_module_activate(GLOBUS_COMMON_MODULE) != GLOBUS_SUCCESS) {
+ fprintf(stderr, "Cannot initialize Globus common module\n");
+ exit(1);
+ }
+
+ edg_wlc_SSLInitialization();
+
+ edg_wll_InitContext(&ctx);
+
+ /* log the event - priority/normal */
+ logev = (pri) ? edg_wll_LogEventSync : edg_wll_LogEvent;
+
+ /* if no job gived - generate some */
+ if (jobid_s == 0) {
+ const char* s;
+ if (!server) {
+ s = "localhost";
+ err = 1; // result fail if used normaly
+ } else
+ s = server;
+ edg_wlc_JobIdCreate(s, 0, &jobid);
+ jobid_s = edg_wlc_JobIdUnparse(jobid);
+ fprintf(stderr, "JobId not given: created %s (server: %s)\n",jobid_s, s);
+ }
+ else if ((errno = edg_wlc_JobIdParse(jobid_s,&jobid))) {
+ perror(jobid_s);
+ exit(1);
+ }
+
+ if (event == EDG_WLL_EVENT_UNDEF) {
+ fprintf(stderr,"%s: unknown or unspecified event\n",argv[0]);
+ exit(1);
+ }
+ edg_wll_SetParam(ctx, EDG_WLL_PARAM_SOURCE, src);
+ if (src_instance) edg_wll_SetParam(ctx, EDG_WLL_PARAM_INSTANCE, src_instance);
+ edg_wll_SetParam(ctx, EDG_WLL_PARAM_LEVEL,
+ (deb) ? EDG_WLL_LEVEL_DEBUG : EDG_WLL_LEVEL_SYSTEM);
+
+ if (edg_wll_SetLoggingJob(ctx,jobid,code,EDG_WLL_SEQ_NORMAL)) {
+ char *et,*ed;
+ edg_wll_Error(ctx,&et,&ed);
+ fprintf(stderr,"SetLoggingJob(%s,%s): %s (%s)\n",jobid_s,code,et,ed);
+ exit(1);
+ }
+
+#ifdef ENABLE_REASON_LENGTH
+ if (elength > 200000000) {
+ fprintf(stderr,"%s: usupported reason message length: %d\n", argv[0], elength);
+ } else if (elength > 0) {
+ int d;
+ int i = 0;
+ reason = realloc(reason, elength + 1);
+ reason[elength] = 0;
+ while (i < (elength)) {
+ if ((i % 20) == 0 && (i + 14) < elength)
+ i += sprintf(reason + i, "%d", i);
+ reason[i++] = '.';
+ }
+ // amount of decimal digits + "end="
+ d = (int)ceil(log(i)/log(10)) + 5;
+ if (i > d)
+ sprintf(reason + i - (int)(d), "end=%d",i);
+ reason[i] = 0;
+ }
+#endif
+#if 0
+ if (fname) {
+ FILE *f = fopen(fname,"r");
+ long s;
+ size_t r;
+
+ fmt = "%s FILE.CONTENT=\"%|Us\" ";
+
+ if (!f) { perror(fname); return 1; }
+ fseek(f,0L,SEEK_END);
+ s = ftell(f); rewind(f);
+ ff = (char *) malloc(s+1); if (!ff) { perror(NULL); return 0; }
+ r = fread(ff,1,s,f);
+ printf("%s: read %d\n",fname,r);
+ ff[s] = 0;
+ fclose(f);
+ }
+ else
+ fmt = "%s ";
+#endif
+
+ //err = edg_wll_LogEvent(ctx, event, fmt, fmt_arg, ff);
+
+ switch (event)
+ {
+@@@{
+$indent = "\t";
+ for my $t (sort { $event->{order}->{$a} <=> $event->{order}->{$b} }
+ $event->getTypes) {
+
+ my $tu = uc $t;
+ gen $indent."case EDG_WLL_EVENT_$tu :\n";
+
+ selectType $event $t;
+ my $argl = "";
+ for ($event->getFieldsOrdered) {
+ my $f = selectField $event $_;
+ my $fn = $f->getName;
+ my $ft;
+
+# gen { $fn $f->{codes} };
+ if ($f->{codes}) {
+# $ft = "enum edg_wll\_$t" . ucfirst $fn;
+ $ft = "char *";
+ } else {
+ $ft = $f->getType;
+ }
+
+ $fn = $f->getType()."ToString($fn)" if $ULMasString{$f->{type}};
+
+ $argl = $argl . ", ";
+ $argl = $argl . $fn;
+ }
+gen qq{\t //edg_wll_Log$t();
+\t err |= logev(ctx, EDG_WLL_EVENT_$tu, EDG_WLL_FORMAT_${tu}$argl);
+\t break;
+};
+ }
+@@@}
+ default:
+ fprintf(stderr, "unknown event\n");
+ }
+
+ edg_wlc_JobIdFree(jobid);
+ if (jobid_s) free(jobid_s); // add all strings
+
+ if (err) {
+ char *et,*ed;
+
+ edg_wll_Error(ctx,&et,&ed);
+ fprintf(stderr,"%s: edg_wll_LogEvent*(): %s (%s)\n",
+ argv[0],et,ed);
+ free(et); free(ed);
+ }
+
+ code = edg_wll_GetSequenceCode(ctx);
+ puts(code);
+ free(code);
+
+ edg_wll_FreeContext(ctx);
+
+ if (ff) free(ff);
+ if (fmt_arg) free(fmt_arg);
+
+ return err;
+}
--- /dev/null
+#ident "$Header"
+
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <netdb.h>
+
+
+#include "glite/lb/notification.h"
+#include "glite/lb/events.h"
+#include "glite/lb/log_proto.h"
+#include "glite/lb/mini_http.h"
+#include "glite/lb/context-int.h"
+#include "glite/lb/xml_parse.h"
+#include "glite/lb/events_parse.h"
+#include "glite/lb/il_string.h"
+#include "glite/lb/escape.h"
+
+#include "connection.h"
+
+#define CON_QUEUE 10 /* listen() queue limit */
+
+/* XXX: moving all request_headers to one file would be nice
+ */
+static const char* const request_headers[] = {
+ "Cache-Control: no-cache",
+ "Accept: application/x-dglb",
+ "User-Agent: edg_wll_Api/" PROTO_VERSION "/" COMP_PROTO,
+ "Content-Type: application/x-dglb",
+ NULL
+};
+
+
+
+
+/* Decrement timeout
+ */
+static int decrement_timeout(struct timeval *timeout, struct timeval before, struct timeval after)
+{
+ if (!timeout)
+ return(0); // wait indefinitely
+
+ (*timeout).tv_sec = (*timeout).tv_sec - (after.tv_sec - before.tv_sec);
+ (*timeout).tv_usec = (*timeout).tv_usec - (after.tv_usec - before.tv_usec);
+ while ( (*timeout).tv_usec < 0) {
+ (*timeout).tv_sec--;
+ (*timeout).tv_usec += 1000000;
+ }
+ if ( ((*timeout).tv_sec < 0) || (((*timeout).tv_sec == 0) && ((*timeout).tv_usec == 0)) ) return(1);
+ else return(0);
+}
+
+
+
+/* Split address to name & port
+ */
+static void get_name_and_port(const char *address, char **name, int *port)
+{
+ char *n = NULL, *p;
+
+ n = strdup(address);
+ p = strchr(n, ':');
+ if (p)
+ {
+ *port = atoi(p+1);
+ *p = 0;
+ }
+ *name = strdup(n);
+ free(n);
+}
+
+
+static int my_bind(edg_wll_Context ctx, const char *name, int port, int *fd)
+{
+ struct sockaddr_in a;
+ socklen_t alen = sizeof(a);
+ int sock;
+
+ sock = socket(PF_INET,SOCK_STREAM,0);
+ if (sock<0)
+ return edg_wll_SetError(ctx, errno, "socket() failed");
+
+ a.sin_family = AF_INET;
+ a.sin_port = htons(port);
+ a.sin_addr.s_addr = name? inet_addr(name): htonl(INADDR_ANY);
+
+// setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one));
+ if (bind(sock,(struct sockaddr *)&a,alen))
+ return edg_wll_SetError(ctx, errno, "bind() failed");
+
+
+ if (listen(sock,CON_QUEUE))
+ return edg_wll_SetError(ctx, errno, "listen() failed");
+
+ *fd = sock;
+
+ return edg_wll_Error(ctx,NULL,NULL);
+}
+
+
+
+static int set_server_name_and_port(edg_wll_Context ctx)
+{
+
+ if (!ctx->p_notif_server)
+ return(edg_wll_SetError(ctx, (edg_wll_ErrorCode) EINVAL,
+ "Hostname of server to notif is not set"));
+ else {
+ free(ctx->srvName);
+ ctx->srvName = strdup(ctx->p_notif_server);
+ }
+ if (!ctx->p_notif_server_port)
+ return(edg_wll_SetError(ctx, (edg_wll_ErrorCode) EINVAL,
+ "Port of server to notif is not set"));
+ else ctx->srvPort = ctx->p_notif_server_port;
+
+ return edg_wll_Error(ctx,NULL,NULL);
+}
+
+
+
+static int get_client_address(
+ edg_wll_Context ctx,
+ int fd,
+ const char *address_override,
+ char **address)
+
+{
+ struct sockaddr_in a;
+ socklen_t alen = sizeof(a);
+ struct hostent *he;
+ char *name = NULL;
+ int port = 0;
+
+
+ if (address_override) {
+ struct in_addr in;
+
+ get_name_and_port(address_override, &name, &port);
+
+ if ( (he = gethostbyname((const char *) name)) == NULL) {
+ edg_wll_SetError(ctx, errno, "gethostbyname() failed");
+ goto err;
+ }
+
+ free(name);
+
+ memmove(&in.s_addr, he->h_addr_list[0], sizeof(in.s_addr));
+ name = strdup(inet_ntoa(in));
+
+ if ( (he = gethostbyname((const char *) name)) == NULL) {
+ edg_wll_SetError(ctx, errno, "gethostbyname() failed");
+ goto err;
+ }
+
+ /* Test whether open sockket represents the same address as address_override
+ * if not, close ctx->notifSock and bind to new socket corresponding to
+ * address_override
+ */
+ if (ctx->notifSock >= 0) {
+ if (getsockname(ctx->notifSock, &a, &alen))
+ return edg_wll_SetError(ctx, errno, "getsockname() failed");
+
+ if ( (strcmp(inet_ntoa(a.sin_addr), name)) || (ntohs(a.sin_port) != port) ) {
+
+ if (close(ctx->notifSock)) {
+ edg_wll_SetError(ctx, errno, "close() failed");
+ goto err;
+ }
+ ctx->notifSock = -1;
+
+ if (my_bind(ctx, name, port, &(ctx->notifSock)))
+ goto err;
+ }
+ }
+ else { // create new socket
+ if (my_bind(ctx, name, port, &(ctx->notifSock)))
+ goto err;
+ }
+
+ *address = strdup(address_override);
+ }
+ else { // address_override == NULL
+
+ if (fd == -1) {
+ if (ctx->notifSock == -1)
+ // create new socket
+ if (my_bind(ctx, NULL, 0, &(ctx->notifSock)))
+ goto err;
+ // else: resue socket
+ }
+ else
+ // used supplied socket
+ ctx->notifSock = fd;
+
+ if (getsockname(ctx->notifSock, &a, &alen))
+ return edg_wll_SetError(ctx, errno, "getsockname() failed");
+
+ if (a.sin_addr.s_addr == INADDR_ANY)
+ asprintf(address,"0.0.0.0:%d", ntohs(a.sin_port));
+ else
+ asprintf(address,"%s:%d", inet_ntoa(a.sin_addr), ntohs(a.sin_port));
+ }
+
+err:
+ free(name);
+
+ return edg_wll_Error(ctx,NULL,NULL);
+}
+
+
+
+int edg_wll_NotifNew(
+ edg_wll_Context ctx,
+ edg_wll_QueryRec const * const *conditions,
+ int fd,
+ const char *address_override,
+ edg_wll_NotifId *id_out,
+ time_t *valid)
+{
+ edg_wll_NotifId notifId = NULL;
+ char *address = NULL, *send_mess = NULL,
+ *recv_mess = NULL, *response = NULL;
+ int ret;
+
+
+ edg_wll_ResetError(ctx);
+
+ if ( (ret = set_server_name_and_port(ctx)) )
+ goto err;
+
+ if ( (ret = edg_wll_NotifIdCreate(ctx->srvName,ctx->srvPort,¬ifId)) )
+ goto err;
+
+ if ( (ret = get_client_address(ctx, fd, address_override, &address)) )
+ goto err;
+
+ if ( (ret = edg_wll_NotifRequestToXML(ctx, "New", notifId, address,
+ EDG_WLL_NOTIF_NOOP, conditions, &send_mess)) )
+ goto err;
+
+ ctx->p_tmp_timeout = ctx->p_notif_timeout;
+
+ if ( (ret = edg_wll_http_send_recv(ctx, "POST /notifRequest HTTP/1.1",
+ request_headers,send_mess,
+ &response,NULL,&recv_mess)) )
+ goto err;
+
+ if ( (ret = http_check_status(ctx,response)) )
+ goto err;
+
+ ret = edg_wll_ParseNotifResult(ctx, recv_mess, valid);
+
+
+err:
+ if (ret != 0) {
+ if (notifId) edg_wll_NotifIdFree(notifId);
+ *id_out = NULL;
+ *valid = -1;
+ }
+ else
+ *id_out = notifId;
+
+ free(address);
+ free(recv_mess);
+ free(send_mess);
+ free(response);
+ return edg_wll_Error(ctx,NULL,NULL);
+}
+
+
+
+int edg_wll_NotifBind(
+ edg_wll_Context ctx,
+ const edg_wll_NotifId id,
+ int fd,
+ const char *address_override,
+ time_t *valid)
+{
+ char *address = NULL, *send_mess = NULL,
+ *recv_mess = NULL, *response = NULL;
+
+
+ edg_wll_ResetError(ctx);
+
+
+ // if a local listening socket active, close it
+ if (ctx->notifSock >= 0) {
+ if (close(ctx->notifSock))
+ return edg_wll_SetError(ctx, errno, "close() failed");
+ else
+ ctx->notifSock = -1;
+ }
+
+ if (set_server_name_and_port(ctx))
+ goto err;
+
+ if (get_client_address(ctx, fd, address_override, &address))
+ goto err;
+
+ if (edg_wll_NotifRequestToXML(ctx, "Bind", id, address,
+ EDG_WLL_NOTIF_NOOP, NULL, &send_mess))
+ goto err;
+
+ ctx->p_tmp_timeout = ctx->p_notif_timeout;
+
+ if (edg_wll_http_send_recv(ctx, "POST /notifRequest HTTP/1.1",
+ request_headers,send_mess,
+ &response,NULL,&recv_mess))
+ goto err;
+
+ if (http_check_status(ctx,response))
+ goto err;
+
+ edg_wll_ParseNotifResult(ctx, recv_mess, valid);
+
+err:
+ free(address);
+ free(recv_mess);
+ free(send_mess);
+ free(response);
+ return edg_wll_Error(ctx,NULL,NULL);
+}
+
+
+
+int edg_wll_NotifChange(
+ edg_wll_Context ctx,
+ const edg_wll_NotifId id,
+ edg_wll_QueryRec const * const * conditions,
+ edg_wll_NotifChangeOp op)
+{
+ char *send_mess = NULL, *recv_mess = NULL, *response = NULL;
+ time_t not_used;
+
+
+ edg_wll_ResetError(ctx);
+
+
+ if (set_server_name_and_port(ctx))
+ goto err;
+
+ if (edg_wll_NotifRequestToXML(ctx, "Change", id, NULL,
+ op, conditions, &send_mess))
+ goto err;
+
+ ctx->p_tmp_timeout = ctx->p_notif_timeout;
+
+ if (edg_wll_http_send_recv(ctx, "POST /notifRequest HTTP/1.1",
+ request_headers,send_mess,
+ &response,NULL,&recv_mess))
+ goto err;
+
+ if (http_check_status(ctx,response))
+ goto err;
+
+ edg_wll_ParseNotifResult(ctx, recv_mess, ¬_used);
+
+err:
+ free(recv_mess);
+ free(send_mess);
+ free(response);
+ return edg_wll_Error(ctx,NULL,NULL);
+}
+
+
+
+int edg_wll_NotifRefresh(
+ edg_wll_Context ctx,
+ const edg_wll_NotifId id,
+ time_t *valid)
+{
+ char *send_mess = NULL, *recv_mess = NULL, *response = NULL;
+
+
+ edg_wll_ResetError(ctx);
+
+
+ if (set_server_name_and_port(ctx))
+ goto err;
+
+ if (edg_wll_NotifRequestToXML(ctx, "Refresh", id, NULL,
+ EDG_WLL_NOTIF_NOOP, NULL, &send_mess))
+ goto err;
+
+ ctx->p_tmp_timeout = ctx->p_notif_timeout;
+
+ if (edg_wll_http_send_recv(ctx, "POST /notifRequest HTTP/1.1",
+ request_headers,send_mess,
+ &response,NULL,&recv_mess))
+ goto err;
+
+ if (http_check_status(ctx,response))
+ goto err;
+
+ edg_wll_ParseNotifResult(ctx, recv_mess, valid);
+
+err:
+ free(recv_mess);
+ free(send_mess);
+ free(response);
+ return edg_wll_Error(ctx,NULL,NULL);
+}
+
+
+
+int edg_wll_NotifDrop(
+ edg_wll_Context ctx,
+ edg_wll_NotifId *id)
+{
+ char *send_mess = NULL, *recv_mess = NULL, *response = NULL;
+ time_t not_used;
+
+
+ edg_wll_ResetError(ctx);
+
+
+ if (set_server_name_and_port(ctx))
+ goto err;
+
+ if (edg_wll_NotifRequestToXML(ctx, "Drop", id, NULL,
+ EDG_WLL_NOTIF_NOOP, NULL, &send_mess))
+ goto err;
+
+ ctx->p_tmp_timeout = ctx->p_notif_timeout;
+
+ if (edg_wll_http_send_recv(ctx, "POST /notifRequest HTTP/1.1",
+ request_headers,send_mess,
+ &response,NULL,&recv_mess))
+ goto err;
+
+ if (http_check_status(ctx,response))
+ goto err;
+
+ edg_wll_ParseNotifResult(ctx, recv_mess, ¬_used);
+
+err:
+ free(recv_mess);
+ free(send_mess);
+ free(response);
+ return edg_wll_Error(ctx,NULL,NULL);
+}
+
+
+
+static int recv_notif(edg_wll_Context ctx)
+{
+ int ret, len;
+ char fbuf[17];
+ size_t total;
+
+
+ if (ctx->connPool[ctx->connToUse].buf) {
+ free(ctx->connPool[ctx->connToUse].buf);
+ ctx->connPool[ctx->connToUse].buf = NULL;
+ }
+ ctx->connPool[ctx->connToUse].bufUse = 0;
+ ctx->connPool[ctx->connToUse].bufSize = 0;
+
+
+ if ((ret=edg_wll_ssl_read_full(ctx->connPool[ctx->connToUse].ssl,
+ fbuf,17,&ctx->p_tmp_timeout,&total)) < 0)
+ switch (ret) {
+ case EDG_WLL_SSL_ERROR_TIMEOUT:
+ return edg_wll_SetError(ctx,ETIMEDOUT,"read message header");
+ case EDG_WLL_SSL_ERROR_EOF:
+ return edg_wll_SetError(ctx,ENOTCONN,NULL);
+ default:
+ return edg_wll_SetError(ctx,EDG_WLL_ERROR_SSL,"read message header");
+ }
+
+ if ((len = atoi(fbuf)) <= 0) {
+ return edg_wll_SetError(ctx,EINVAL,"message length");
+ }
+
+ ctx->connPool[ctx->connToUse].bufSize = len+1;
+
+ ctx->connPool[ctx->connToUse].buf = (char *) malloc(
+ ctx->connPool[ctx->connToUse].bufSize);
+
+ if (!ctx->connPool[ctx->connToUse].buf) {
+ return edg_wll_SetError(ctx, ENOMEM, "recv_notif()");
+ }
+
+
+ if ((ret=edg_wll_ssl_read_full(ctx->connPool[ctx->connToUse].ssl,
+ ctx->connPool[ctx->connToUse].buf,
+ len,
+ &ctx->p_tmp_timeout,&total)) < 0) {
+ free(ctx->connPool[ctx->connToUse].buf);
+ ctx->connPool[ctx->connToUse].bufUse = 0;
+ ctx->connPool[ctx->connToUse].bufSize = 0;
+ return edg_wll_SetError(ctx,
+ ret == EDG_WLL_SSL_ERROR_TIMEOUT ?
+ ETIMEDOUT : EDG_WLL_ERROR_SSL,
+ "read message");
+ }
+
+
+ ctx->connPool[ctx->connToUse].buf[len] = 0;
+ ctx->connPool[ctx->connToUse].bufUse = len+1;
+
+
+ return edg_wll_Error(ctx,NULL,NULL);
+}
+
+
+
+static int send_reply(const edg_wll_Context ctx)
+{
+ int ret, len, err_code, err_code_min = 0, max_len = 256;
+ char *p, *err_msg = NULL, buf[max_len];
+ size_t total;
+
+
+ err_code = edg_wll_Error(ctx,NULL,&err_msg);
+
+ if (!err_msg) err_msg=strdup("OK");
+
+ len = 17 + len_int(err_code) + len_int(err_code_min) +len_string(err_msg);
+ if(len > max_len) {
+ edg_wll_SetError(ctx,E2BIG,"create_reply()");
+ goto err;
+ }
+
+ snprintf(buf, max_len, "%16d\n", len - 17);
+ p = buf + 17;
+ p = put_int(p, err_code);
+ p = put_int(p, err_code_min);
+ p = put_string(p, err_msg);
+
+
+ if ((ret = edg_wll_ssl_write_full(ctx->connPool[ctx->connToUse].ssl,
+ buf,len,&ctx->p_tmp_timeout,&total)) < 0) {
+ edg_wll_SetError(ctx,
+ ret == EDG_WLL_SSL_ERROR_TIMEOUT ?
+ ETIMEDOUT : EDG_WLL_ERROR_SSL,
+ "write reply");
+ goto err;
+ }
+
+err:
+ free(err_msg);
+ return edg_wll_Error(ctx,NULL,NULL);
+}
+
+
+
+int edg_wll_NotifReceive(
+ edg_wll_Context ctx,
+ int fd,
+ const struct timeval *timeout,
+ edg_wll_JobStat *state_out,
+ edg_wll_NotifId *id_out)
+{
+ fd_set fds;
+ struct sockaddr_in a;
+ int recv_sock, alen;
+ edg_wll_Event *event = NULL;
+ struct timeval start_time,check_time,tv;
+ char *p = NULL, *ucs = NULL,
+ *event_char = NULL, *jobstat_char = NULL;
+
+
+
+/* start timer */
+ gettimeofday(&start_time,0);
+
+ if (fd == -1) {
+ if (ctx->notifSock == -1) {
+ edg_wll_SetError(ctx, EINVAL, "No client socket opened.");
+ goto err;
+ }
+ else {
+ fd = ctx->notifSock;
+ }
+ }
+
+ FD_ZERO(&fds);
+ FD_SET(fd,&fds);
+
+ tv.tv_sec = timeout->tv_sec;
+ tv.tv_usec = timeout->tv_usec;
+
+ switch(select(fd+1, &fds, NULL, NULL, &tv)) {
+ case -1:
+ edg_wll_SetError(ctx, errno, "select() failed");
+ goto err;
+ case 0:
+ edg_wll_SetError(ctx, ETIMEDOUT, "select() timeouted");
+ goto err;
+ default:
+ break;
+ }
+
+/* check time */
+ gettimeofday(&check_time,0);
+ if (decrement_timeout(&tv, start_time, check_time)) {
+ edg_wll_SetError(ctx, ETIMEDOUT, "edg_wll_NotifReceive()");
+ goto err;
+ }
+
+ start_time = check_time;
+
+ alen=sizeof(a);
+ recv_sock = accept(fd,&a,&alen);
+ if (recv_sock <0) {
+ edg_wll_SetError(ctx, errno, "accept() failed");
+ goto err;
+ }
+
+
+ ctx->connPool[ctx->connToUse].ssl =
+ edg_wll_ssl_accept(ctx->connPool[ctx->connToUse].gsiCred,recv_sock,&tv);
+
+ if (ctx->connPool[ctx->connToUse].ssl == NULL) {
+ edg_wll_SetError(ctx, errno, "SSL hanshake failed.");
+ goto err;
+ }
+
+/* check time */
+ gettimeofday(&check_time,0);
+ if (decrement_timeout(&tv, start_time, check_time)) {
+ edg_wll_SetError(ctx, ETIMEDOUT, "edg_wll_NotifReceive()");
+ goto err;
+ }
+
+ start_time = check_time;
+
+
+ ctx->p_tmp_timeout = tv;
+
+ if (recv_notif(ctx)) {
+ /* error set in recv_notif() */
+ goto err;
+ }
+
+ if (send_reply(ctx)) {
+ /* error set in send_reply() */
+ goto err;
+ }
+
+ p = ctx->connPool[ctx->connToUse].buf;
+ p = get_string(p, &ucs);
+ if (p == NULL) return edg_wll_SetError(ctx,EDG_WLL_IL_PROTO,"reading UCS");
+ free(ucs);
+
+ p = get_string(p, &event_char);
+ if (p == NULL) {
+ free(ucs);
+ return edg_wll_SetError(ctx,EDG_WLL_IL_PROTO,"reading event string");;
+ }
+
+/* check time */
+ gettimeofday(&check_time,0);
+ if (decrement_timeout(&tv, start_time, check_time)) {
+ edg_wll_SetError(ctx, ETIMEDOUT, "edg_wll_NotifReceive()");
+ goto err;
+ }
+
+ start_time = check_time;
+
+ event = edg_wll_InitEvent(EDG_WLL_EVENT_NOTIFICATION);
+ if (edg_wll_ParseNotifEvent(ctx, event_char, &event)) {
+ goto err;
+ }
+
+ jobstat_char = edg_wll_UnescapeXML((const char *) event->notification.jobstat);
+ if (jobstat_char == NULL) {
+ edg_wll_SetError(ctx, EINVAL, "edg_wll_UnescapeXML()");
+ goto err;
+ }
+
+ /* fill in return values
+ */
+ if ( edg_wll_ParseJobStat(ctx, jobstat_char,
+ strlen(jobstat_char), state_out)) {
+ goto err;
+ }
+
+ *id_out = event->notification.notifId;
+ event->notification.notifId = NULL;
+
+
+err:
+ if (event) {
+ edg_wll_FreeEvent(event);
+ // XXX - konzultovat s honikem; podle meho by to free
+ // mel delat uz edg_wll_FreeEvent
+ //free(event);
+ }
+
+ free(ctx->connPool[ctx->connToUse].buf);
+ ctx->connPool[ctx->connToUse].buf = NULL;
+ ctx->connPool[ctx->connToUse].bufUse = 0;
+ ctx->connPool[ctx->connToUse].bufSize = 0;
+
+ free(event_char);
+ free(jobstat_char);
+
+ // XXX
+ // konzultovat s Danem
+ edg_wll_ssl_close(ctx->connPool[ctx->connToUse].ssl);
+ ctx->connPool[ctx->connToUse].ssl = NULL;
+
+ return edg_wll_Error(ctx,NULL,NULL);
+}
+
+
+int edg_wll_NotifGetFd(
+ edg_wll_Context ctx)
+{
+ if (ctx->notifSock == -1) {
+ edg_wll_SetError(ctx, EBADF, "Client socket is not opened.");
+ return -1;
+ }
+
+ return ctx->notifSock;
+}
+
+
+int edg_wll_NotifCloseFd(
+ edg_wll_Context ctx)
+{
+ int err;
+
+ if (ctx->notifSock >= 0) {
+ if (ctx->connPool[ctx->connToUse].ssl) {
+ edg_wll_ssl_close(ctx->connPool[ctx->connToUse].ssl);
+ ctx->connPool[ctx->connToUse].ssl = NULL;
+ }
+ err = close(ctx->notifSock);
+ ctx->notifSock = -1;
+
+ if (err)
+ return edg_wll_SetError(ctx, errno, "close() failed");
+ }
+
+ return edg_wll_Error(ctx,NULL,NULL);
+}
--- /dev/null
+#ident "$Header$"
+
+#include "prod_proto.h"
+#include "glite/lb/producer.h"
+#include "glite/lb/escape.h"
+
+#include <signal.h>
+#include <string.h>
+#include <sys/types.h>
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * edg_wll_log_proto_client - handle outgoing data
+ *
+ * Returns: 0 if done properly or errno
+ *
+ * Calls:
+ *
+ * Algorithm:
+ *
+ *----------------------------------------------------------------------
+ */
+int edg_wll_log_proto_client(edg_wll_Context context, SSL *ssl, edg_wll_LogLine logline/*, int priority,*/)
+{
+ char header[EDG_WLL_LOG_SOCKET_HEADER_LENGTH+1];
+ int err;
+ int answer;
+ u_int8_t answer_end[4];
+ int count;
+ int size;
+ u_int8_t size_end[4];
+
+ errno = err = answer = count = 0;
+ size = strlen(logline)+1;
+ size_end[0] = size & 0xff; size >>= 8;
+ size_end[1] = size & 0xff; size >>= 8;
+ size_end[2] = size & 0xff; size >>= 8;
+ size_end[3] = size;
+ size = strlen(logline)+1;
+ edg_wll_ResetError(context);
+
+ /* send header */
+#ifdef EDG_WLL_LOG_STUB
+ fprintf(stderr,"Sending socket header...\n");
+#endif
+ sprintf(header,"%s",EDG_WLL_LOG_SOCKET_HEADER);
+ header[EDG_WLL_LOG_SOCKET_HEADER_LENGTH]='\0';
+ if ((err = edg_wll_ssl_write_full(ssl, header, EDG_WLL_LOG_SOCKET_HEADER_LENGTH, &context->p_tmp_timeout, &count)) < 0) {
+ answer = edg_wll_log_proto_client_failure(context,err,"send header");
+ goto edg_wll_log_proto_client_end;
+ }
+
+/* XXX: obsolete
+#ifdef EDG_WLL_LOG_STUB
+ fprintf(stderr,"Sending message priority...\n");
+#endif
+ count = 0;
+ if ((err = edg_wll_ssl_write_full(ssl, &priority, sizeof(priority), &context->p_tmp_timeout, &count)) < 0) {
+ answer = edg_wll_log_proto_client_failure(context,err,"send message priority");
+ goto edg_wll_log_proto_client_end;
+ }
+*/
+
+#ifdef EDG_WLL_LOG_STUB
+ fprintf(stderr,"Sending message size...\n");
+#endif
+ count = 0;
+ if ((err = edg_wll_ssl_write_full(ssl, size_end, 4, &context->p_tmp_timeout, &count)) < 0) {
+ answer = edg_wll_log_proto_client_failure(context,err,"send message size");
+ goto edg_wll_log_proto_client_end;
+ }
+
+ /* send message */
+#ifdef EDG_WLL_LOG_STUB
+ fprintf(stderr,"Sending message to socket...\n");
+#endif
+ count = 0;
+ if (( err = edg_wll_ssl_write_full(ssl, logline, size, &context->p_tmp_timeout, &count)) < 0) {
+ answer = edg_wll_log_proto_client_failure(context,err,"send message");
+ goto edg_wll_log_proto_client_end;
+ }
+
+ /* get answer */
+#ifdef EDG_WLL_LOG_STUB
+ fprintf(stderr,"Reading answer from server...\n");
+#endif
+ count = 0;
+ if ((err = edg_wll_ssl_read_full(ssl, answer_end, 4, &context->p_tmp_timeout, &count)) < 0 ) {
+ answer = edg_wll_log_proto_client_failure(context,err,"get answer");
+/* FIXME: update the answer (in context?) to EAGAIN or not?
+ answer = EAGAIN;
+*/
+ } else {
+ answer = answer_end[3]; answer <<=8;
+ answer |= answer_end[2]; answer <<=8;
+ answer |= answer_end[1]; answer <<=8;
+ answer |= answer_end[0];
+#ifdef EDG_WLL_LOG_STUB
+ fprintf(stderr,"Read answer \"%d\"\n",answer);
+#endif
+ edg_wll_SetError(context,answer,"answer read from locallogger");
+ }
+
+edg_wll_log_proto_client_end:
+
+ return edg_wll_Error(context,NULL,NULL);
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * edg_wll_log_proto_client_failure - handle protocol failures on the client side
+ *
+ * Returns: errno
+ *
+ *----------------------------------------------------------------------
+ */
+int edg_wll_log_proto_client_failure(edg_wll_Context context, int code, const char *text)
+{
+ const char *func="edg_wll_log_proto_client()";
+ static char err[256];
+ int ret = 0;
+
+ edg_wll_ResetError(context);
+
+ if(code>0)
+ return(0);
+
+ switch(code) {
+ case EDG_WLL_SSL_ERROR_EOF:
+ snprintf(err, sizeof(err), "%s: Error %s, EOF occured;", func, text);
+ ret = edg_wll_SetError(context,ENOTCONN,err);
+ break;
+ case EDG_WLL_SSL_ERROR_TIMEOUT:
+ snprintf(err, sizeof(err), "%s: Error %s, timeout expired;", func, text);
+ ret = edg_wll_SetError(context,ENOTCONN,err);
+ break;
+ case EDG_WLL_SSL_ERROR_ERRNO: // XXX: perror("edg_wll_ssl_read()"); break;
+ snprintf(err, sizeof(err), "%s: Error %s, system error occured;", func, text);
+ ret = edg_wll_SetError(context,ENOTCONN,err);
+ break;
+ case EDG_WLL_SSL_ERROR_SSL:
+ snprintf(err, sizeof(err), "%s: Error %s, SSL error occured; %s;", func, text,
+ ERR_reason_error_string(ERR_get_error()));
+ ret = edg_wll_SetError(context,ENOTCONN,err);
+ break;
+ default:
+ break;
+ }
+ return ret;
+}
--- /dev/null
+#ifndef __EDG_WORKLOAD_LOGGING_CLIENT_PROD_PROTO_H__
+#define __EDG_WORKLOAD_LOGGING_CLIENT_PROD_PROTO_H__
+
+#ident "$Header$"
+
+/**
+ * \file edg/workload/logging/client/prod_proto.h
+ * \brief client (producer) part of the logging protocol
+ * \note private
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+#include "glite/lb/log_proto.h"
+#include "glite/lb/context-int.h"
+#include "glite/lb/dgssl.h"
+
+int edg_wll_log_proto_client(edg_wll_Context context, SSL *ssl, edg_wll_LogLine logline/*, int priority,*/);
+int edg_wll_log_proto_client_failure(edg_wll_Context context, int code, const char *text);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __EDG_WORKLOAD_LOGGING_CLIENT_PROD_PROTO_H__ */
--- /dev/null
+/**
+ * \file producer.c
+ * \author Jan Pospisil
+ */
+
+#ident "$Header$"
+
+#include <globus_gss_assist.h>
+#include <globus_config.h>
+
+#include <syslog.h>
+#include <string.h>
+#include <unistd.h>
+#include <netdb.h>
+
+#include "glite/wms/thirdparty/globus_ssl_utils/sslutils.h"
+#include "glite/wms/jobid/strmd5.h"
+#include "glite/lb/consumer.h"
+#include "glite/lb/producer.h"
+#include "glite/lb/context-int.h"
+#include "glite/lb/ulm_parse.h"
+#include "glite/lb/trio.h"
+
+#include "prod_proto.h"
+
+/**
+ *----------------------------------------------------------------------
+ * Connects to local-logger and sends already formatted ULM string
+ * \brief helper logging function
+ * \param context INOUT context to work with,
+ * \param priority IN priority flag (0 for async, 1 for sync)
+ * \param logline IN formated ULM string
+ *----------------------------------------------------------------------
+ */
+static int edg_wll_DoLogEvent(
+ edg_wll_Context context,
+/* int priority, */
+ edg_wll_LogLine logline)
+{
+ int ret,answer;
+ void *cred_handle = NULL;
+ SSL *ssl = NULL;
+#ifdef EDG_WLL_LOG_STUB
+ char *my_subject_name = NULL;
+#endif
+
+ edg_wll_ResetError(context);
+ ret = answer = 0;
+
+ /* open a SSL connection to the local-logger: */
+
+#ifdef EDG_WLL_LOG_STUB
+ fprintf(stderr,"Logging to host %s, port %d\n",
+ context->p_destination, context->p_dest_port);
+#endif
+
+ if ((cred_handle=edg_wll_ssl_init(SSL_VERIFY_PEER, 0,
+ context->p_proxy_filename ? context->p_proxy_filename : context->p_cert_filename,
+ context->p_proxy_filename ? context->p_proxy_filename : context->p_key_filename,
+ 0, 0)) == NULL) {
+ edg_wll_SetError(context,EDG_WLL_ERROR_SSL,"edg_wll_ssl_init()");
+ goto edg_wll_DoLogEvent_end;
+ }
+#ifdef EDG_WLL_LOG_STUB
+ edg_wll_ssl_get_my_subject(cred_handle,&my_subject_name);
+ if (my_subject_name != NULL) {
+ fprintf(stderr,"Using certificate: %s\n",my_subject_name);
+ free(my_subject_name);
+ } else {
+ edg_wll_SetError(context,ECONNREFUSERD,"edg_wll_ssl_get_my_subject()");
+ goto edg_wll_DoLogEvent_end;
+ }
+#endif
+ if ((answer = edg_wll_ssl_connect(cred_handle,
+ context->p_destination, context->p_dest_port,
+ &context->p_tmp_timeout, &ssl)) < 0) {
+ switch(answer) {
+ case EDG_WLL_SSL_ERROR_EOF:
+ edg_wll_SetError(context,ENOTCONN,"edg_wll_ssl_connect()");
+ break;
+ case EDG_WLL_SSL_ERROR_TIMEOUT:
+ edg_wll_SetError(context,ETIMEDOUT,"edg_wll_ssl_connect()");
+ break;
+ case EDG_WLL_SSL_ERROR_ERRNO:
+ edg_wll_SetError(context,errno,"edg_wll_ssl_connect()");
+ break;
+ case EDG_WLL_SSL_ERROR_SSL:
+ {
+ const char *msg1;
+ char *msg2;
+ msg1 = ERR_reason_error_string(ERR_get_error());
+ asprintf(&msg2, "edg_wll_ssl_connect(): %s", msg1);
+ edg_wll_SetError(context,EDG_WLL_ERROR_SSL,msg2);
+ free(msg2);
+ }
+ break;
+ case EDG_WLL_SSL_ERROR_HERRNO:
+ {
+ const char *msg1;
+ char *msg2;
+ msg1 = hstrerror(errno);
+ asprintf(&msg2, "edg_wll_ssl_connect(): %s", msg1);
+ edg_wll_SetError(context,EDG_WLL_ERROR_DNS, msg2);
+ free(msg2);
+ }
+ break;
+ default:
+ edg_wll_SetError(context,ECONNREFUSED,"edg_wll_ssl_connect(): unknown");
+ break;
+ }
+ goto edg_wll_DoLogEvent_end;
+ }
+
+ /* and send the message to the local-logger: */
+
+ answer = edg_wll_log_proto_client(context,ssl,logline/*,priority*/);
+
+ switch(answer) {
+ case 0:
+ case EINVAL:
+ case ENOSPC:
+ case ENOMEM:
+ case EDG_WLL_ERROR_SSL:
+ case EDG_WLL_ERROR_DNS:
+ case ENOTCONN:
+ case ECONNREFUSED:
+ case ETIMEDOUT:
+ case EAGAIN:
+ break;
+ case EDG_WLL_ERROR_PARSE_EVENT_UNDEF:
+ case EDG_WLL_ERROR_PARSE_MSG_INCOMPLETE:
+ case EDG_WLL_ERROR_PARSE_KEY_DUPLICITY:
+ case EDG_WLL_ERROR_PARSE_KEY_MISUSE:
+// case EDG_WLL_ERROR_PARSE_OK_WITH_EXTRA_FIELDS:
+ edg_wll_UpdateError(context,EINVAL,"edg_wll_DoLogEvent(): Error code mapped to EINVAL");
+ break;
+ case EDG_WLL_IL_PROTO:
+ case EDG_WLL_IL_SYS:
+ case EDG_WLL_IL_EVENTS_WAITING:
+ edg_wll_UpdateError(context,EAGAIN,"edg_wll_DoLogEvent(): Error code mapped to EAGAIN");
+ break;
+
+ default:
+ edg_wll_UpdateError(context,EAGAIN,"edg_wll_DoLogEvent(): Error code mapped to EAGAIN");
+ break;
+ }
+
+edg_wll_DoLogEvent_end:
+ if (ssl) edg_wll_ssl_close_timeout(ssl,&context->p_tmp_timeout);
+ if (cred_handle) edg_wll_ssl_free(cred_handle);
+
+ return edg_wll_Error(context, NULL, NULL);
+}
+
+
+/**
+ *----------------------------------------------------------------------
+ * Formats a logging message and sends it to local-logger
+ * \brief master logging event function
+ * \param context INOUT context to work with,
+ * \param priority IN priority flag (0 for async, 1 for sync)
+ * \param event IN type of the event,
+ * \param fmt IN printf()-like format string,
+ * \param ... IN event specific values/data according to fmt.
+ *----------------------------------------------------------------------
+ */
+static int edg_wll_LogEventMaster(
+ edg_wll_Context context,
+ int priority,
+ edg_wll_EventCode event,
+ char *fmt, ...)
+{
+ va_list fmt_args;
+ int ret,answer;
+ char *fix,*var;
+ char *source,*eventName,*lvl, *fullid,*seq;
+ struct timeval start_time;
+ char date[ULM_DATE_STRING_LENGTH+1];
+ edg_wll_LogLine out;
+ size_t size;
+ int i;
+
+ i = errno = size = 0;
+ seq = fix = var = out = source = eventName = lvl = fullid = NULL;
+
+ edg_wll_ResetError(context);
+
+ /* default return value is "Try Again" */
+ answer = ret = EAGAIN;
+
+ /* format the message: */
+ va_start(fmt_args,fmt);
+
+ gettimeofday(&start_time,0);
+ if (edg_wll_ULMTimevalToDate(start_time.tv_sec,start_time.tv_usec,date) != 0) {
+ edg_wll_SetError(context,ret = EINVAL,"edg_wll_LogEventMaster(): edg_wll_ULMTimevalToDate() error");
+ goto edg_wll_logeventmaster_end;
+ }
+ source = edg_wll_SourceToString(context->p_source);
+ lvl = edg_wll_LevelToString(context->p_level);
+ eventName = edg_wll_EventToString(event);
+ if (!eventName) {
+ edg_wll_SetError(context,ret = EINVAL,"edg_wll_LogEventMaster(): event name not specified");
+ goto edg_wll_logeventmaster_end;
+ }
+ if (!(fullid = edg_wlc_JobIdUnparse(context->p_jobid))) {
+ edg_wll_SetError(context,ret = EINVAL,"edg_wll_LogEventMaster(): edg_wlc_JobIdUnparse() error");
+ goto edg_wll_logeventmaster_end;
+ }
+ seq = edg_wll_GetSequenceCode(context);
+ if (edg_wll_IncSequenceCode(context)) {
+ ret = EINVAL;
+ goto edg_wll_logeventmaster_end;
+ }
+ if (trio_asprintf(&fix,EDG_WLL_FORMAT_COMMON,
+ date,context->p_host,lvl,priority,
+ source,context->p_instance ? context->p_instance : "",
+ eventName,fullid,seq) == -1) {
+ edg_wll_SetError(context,ret = ENOMEM,"edg_wll_LogEventMaster(): trio_asprintf() error");
+ goto edg_wll_logeventmaster_end;
+ }
+ if (trio_vasprintf(&var,fmt,fmt_args) == -1) {
+ edg_wll_SetError(context,ret = ENOMEM,"edg_wll_LogEventMaster(): trio_vasprintf() error");
+ goto edg_wll_logeventmaster_end;
+ }
+ if (asprintf(&out,"%s%s\n",fix,var) == -1) {
+ edg_wll_SetError(context,ret = ENOMEM,"edg_wll_LogEventMaster(): asprintf() error");
+ goto edg_wll_logeventmaster_end;
+ }
+ size = strlen(out);
+
+ if (priority && (size > EDG_WLL_LOG_SYNC_MAXMSGSIZE)) {
+ edg_wll_SetError(context,ret = ENOSPC,"edg_wll_LogEventMaster(): Message size too large for synchronous transfer");
+ goto edg_wll_logeventmaster_end;
+ }
+
+#ifdef EDG_WLL_LOG_STUB
+// fprintf(stderr,"edg_wll_LogEvent (%d chars): %s",size,out);
+#endif
+
+ context->p_tmp_timeout.tv_sec = 0;
+ context->p_tmp_timeout.tv_usec = 0;
+ if (priority) {
+ context->p_tmp_timeout = context->p_sync_timeout;
+ }
+ else {
+ context->p_tmp_timeout = context->p_log_timeout;
+ }
+
+ /* and send the message to the local-logger: */
+ ret = edg_wll_DoLogEvent(context, /* priority,*/ out);
+
+edg_wll_logeventmaster_end:
+ va_end(fmt_args);
+ if (seq) free(seq);
+ if (fix) free(fix);
+ if (var) free(var);
+ if (out) free(out);
+ if (source) free(source);
+ if (lvl) free(lvl);
+ if (eventName) free(eventName);
+ if (fullid) free(fullid);
+
+ if (ret) edg_wll_UpdateError(context,0,"Logging library ERROR: ");
+
+ return edg_wll_Error(context,NULL,NULL);
+}
+
+/**
+ *----------------------------------------------------------------------
+ * Formats a logging message and sends it asynchronously to local-logger
+ * \brief generic asynchronous logging function
+ *----------------------------------------------------------------------
+ */
+int edg_wll_LogEvent(
+ edg_wll_Context context,
+ edg_wll_EventCode event,
+ char *fmt, ...)
+{
+ int ret=0;
+ char *list=NULL;
+ va_list fmt_args;
+
+ edg_wll_ResetError(context);
+
+ va_start(fmt_args,fmt);
+ if (trio_vasprintf(&list,fmt,fmt_args) == -1) {
+ edg_wll_SetError(context,ret = ENOMEM,"edg_wll_LogEvent(): trio_vasprintf() error");
+ goto edg_wll_logevent_end;
+ }
+
+ ret=edg_wll_LogEventMaster(context,0,event,"%s",list);
+
+edg_wll_logevent_end:
+ va_end(fmt_args);
+ if (list) free(list);
+
+ if (ret) edg_wll_UpdateError(context,0,"edg_wll_LogEvent(): ");
+
+ return edg_wll_Error(context,NULL,NULL);
+}
+
+/**
+ *----------------------------------------------------------------------
+ * Formats a logging message and sends it synchronously to local-logger
+ * \brief generic synchronous logging function
+ * \note simple wrapper around edg_wll_LogEventMaster()
+ *----------------------------------------------------------------------
+ */
+int edg_wll_LogEventSync(
+ edg_wll_Context context,
+ edg_wll_EventCode event,
+ char *fmt, ...)
+{
+ int ret=0;
+ char *list=NULL;
+ va_list fmt_args;
+
+ edg_wll_ResetError(context);
+
+ va_start(fmt_args,fmt);
+ if (trio_vasprintf(&list,fmt,fmt_args) == -1) {
+ edg_wll_SetError(context,ret = ENOMEM,"edg_wll_LogEventSync(): trio_vasprintf() error");
+ goto edg_wll_logeventsync_end;
+ }
+
+ ret=edg_wll_LogEventMaster(context,1,event,"%s",list);
+
+edg_wll_logeventsync_end:
+ va_end(fmt_args);
+ if (list) free(list);
+
+ if (ret) edg_wll_UpdateError(context,0,"edg_wll_LogEventSync(): ");
+
+ return edg_wll_Error(context,NULL,NULL);
+}
+
+
+/**
+ *-----------------------------------------------------------------------
+ * Instructs interlogger to to deliver all pending events related to current job
+ * \brief flush events from interlogger
+ * \note simple wrapper around edg_wll_LogEventMaster()
+ *-----------------------------------------------------------------------
+ */
+int edg_wll_LogFlush(
+ edg_wll_Context context,
+ struct timeval *timeout)
+{
+ int ret = 0;
+ edg_wll_LogLine out = NULL;
+ char *fullid;
+ char date[ULM_DATE_STRING_LENGTH+1];
+ struct timeval start_time;
+
+ fullid = NULL;
+
+ edg_wll_ResetError(context);
+
+ gettimeofday(&start_time, 0);
+ if (edg_wll_ULMTimevalToDate(start_time.tv_sec, start_time.tv_usec, date) != 0) {
+ edg_wll_SetError(context,ret = EINVAL,"edg_wll_ULMTimevalToDate()");
+ goto edg_wll_logflush_end;
+ }
+ if (!(fullid = edg_wlc_JobIdUnparse(context->p_jobid))) {
+ ret = edg_wll_SetError(context,EINVAL,"edg_wlc_JobIdUnparse()");
+ goto edg_wll_logflush_end;
+ }
+
+ if (trio_asprintf(&out, "DATE=%s HOST=\"%|Us\" PROG=internal LVL=system DG.PRIORITY=1 DG.TYPE=\"command\" DG.COMMAND=\"flush\" DG.TIMEOUT=\"%d\" DG.JOBID=\"%s\"\n",
+ date, context->p_host, (timeout ? timeout->tv_sec : context->p_sync_timeout.tv_sec), fullid) == -1) {
+ edg_wll_SetError(context,ret = EINVAL,"trio_asprintf");
+ goto edg_wll_logflush_end;
+ }
+
+ if (timeout)
+ context->p_tmp_timeout = *timeout;
+ else
+ context->p_tmp_timeout = context->p_sync_timeout;
+
+ ret = edg_wll_DoLogEvent(context, /* 1,*/ out);
+
+edg_wll_logflush_end:
+ if(out) free(out);
+ if(fullid) free(fullid);
+
+ if (ret) edg_wll_UpdateError(context,0,"edg_wll_LogFlush(): ");
+
+ return edg_wll_Error(context,NULL,NULL);
+}
+
+/**
+ *-----------------------------------------------------------------------
+ * Instructs interlogger to to deliver all pending events
+ * \brief flush all events from interlogger
+ *-----------------------------------------------------------------------
+ */
+int edg_wll_LogFlushAll(
+ edg_wll_Context context,
+ struct timeval *timeout)
+{
+ int ret = 0;
+ edg_wll_LogLine out = NULL;
+ char date[ULM_DATE_STRING_LENGTH+1];
+ struct timeval start_time;
+
+ edg_wll_ResetError(context);
+
+ gettimeofday(&start_time, 0);
+ if (edg_wll_ULMTimevalToDate(start_time.tv_sec, start_time.tv_usec, date) != 0) {
+ edg_wll_SetError(context,ret = EINVAL,"edg_wll_ULMTimevalToDate()");
+ goto edg_wll_logflushall_end;
+ }
+
+ if (trio_asprintf(&out, "DATE=%s HOST=\"%|Us\" PROG=internal LVL=system DG.PRIORITY=1 DG.TYPE=\"command\" DG.COMMAND=\"flush\" DG.TIMEOUT=\"%d\"\n",
+ date, context->p_host, (timeout ? timeout->tv_sec : context->p_sync_timeout.tv_sec)) == -1) {
+ edg_wll_SetError(context,ret = ENOMEM,"trio_asprintf");
+ goto edg_wll_logflushall_end;
+ }
+
+ if (timeout)
+ context->p_tmp_timeout = *timeout;
+ else
+ context->p_tmp_timeout = context->p_sync_timeout;
+
+ ret = edg_wll_DoLogEvent(context, /* 1,*/ out);
+
+edg_wll_logflushall_end:
+ if(out) free(out);
+
+ if (ret) edg_wll_UpdateError(context,0,"edg_wll_LogFlushAll(): ");
+
+ return edg_wll_Error(context,NULL,NULL);
+}
+
+/**
+ *-----------------------------------------------------------------------
+ * Set a current job for given context.
+ * \note Should be called before any logging call.
+ *-----------------------------------------------------------------------
+ */
+int edg_wll_SetLoggingJob(
+ edg_wll_Context context,
+ const edg_wlc_JobId job,
+ const char *code,
+ int flags)
+{
+ int err;
+
+ edg_wll_ResetError(context);
+
+ if (!job) return edg_wll_SetError(context,EINVAL,"jobid is null");
+
+ edg_wlc_JobIdFree(context->p_jobid);
+ if ((err = edg_wlc_JobIdDup(job,&context->p_jobid)))
+ edg_wll_SetError(context,err,"edg_wll_SetLoggingJob(): edg_wlc_JobIdDup() error");
+
+ else {
+ if (!edg_wll_SetSequenceCode(context,code,flags))
+ edg_wll_IncSequenceCode(context);
+ }
+
+ return edg_wll_Error(context,NULL,NULL);
+}
+
+/**
+ *-----------------------------------------------------------------------
+ * Register job with L&B service.
+ *-----------------------------------------------------------------------
+ */
+static int edg_wll_RegisterJobMaster(
+ edg_wll_Context context,
+ int pri,
+ const edg_wlc_JobId job,
+ enum edg_wll_RegJobJobtype type,
+ const char * jdl,
+ const char * ns,
+ edg_wlc_JobId parent,
+ int num_subjobs,
+ const char * seed,
+ edg_wlc_JobId ** subjobs)
+{
+ char *type_s = NULL,*intseed = NULL, *seq = NULL;
+ char *parent_s = NULL;
+ int err = 0;
+
+ edg_wll_ResetError(context);
+
+ intseed = seed ? strdup(seed) :
+ str2md5base64(seq = edg_wll_GetSequenceCode(context));
+
+ free(seq);
+
+ type_s = edg_wll_RegJobJobtypeToString(type);
+ if (!type_s) return edg_wll_SetError(context,EINVAL,"edg_wll_RegisterJobMaster(): no jobtype specified");
+
+ if ((type == EDG_WLL_REGJOB_DAG || type == EDG_WLL_REGJOB_PARTITIONED)
+ && num_subjobs > 0)
+ err = edg_wll_GenerateSubjobIds(context,job,
+ num_subjobs,intseed,subjobs);
+
+ parent_s = parent ? edg_wlc_JobIdUnparse(parent) : strdup("");
+
+ if (err == 0 &&
+ edg_wll_SetLoggingJob(context,job,NULL,EDG_WLL_SEQ_NORMAL) == 0)
+ edg_wll_LogEventMaster(context,pri,
+ EDG_WLL_EVENT_REGJOB,EDG_WLL_FORMAT_REGJOB,
+ (char *)jdl,ns,parent_s,type_s,num_subjobs,intseed);
+
+ free(type_s); free(intseed); free(parent_s);
+ return edg_wll_Error(context,NULL,NULL);
+}
+
+int edg_wll_RegisterJobSync(
+ edg_wll_Context context,
+ const edg_wlc_JobId job,
+ enum edg_wll_RegJobJobtype type,
+ const char * jdl,
+ const char * ns,
+ int num_subjobs,
+ const char * seed,
+ edg_wlc_JobId ** subjobs)
+{
+ return edg_wll_RegisterJobMaster(context,1,job,type,jdl,ns, NULL, num_subjobs,seed,subjobs);
+}
+
+int edg_wll_RegisterJob(
+ edg_wll_Context context,
+ const edg_wlc_JobId job,
+ enum edg_wll_RegJobJobtype type,
+ const char * jdl,
+ const char * ns,
+ int num_subjobs,
+ const char * seed,
+ edg_wlc_JobId ** subjobs)
+{
+ return edg_wll_RegisterJobMaster(context,0,job,type,jdl,ns, NULL, num_subjobs,seed,subjobs);
+}
+
+int edg_wll_RegisterSubjob(
+ edg_wll_Context context,
+ const edg_wlc_JobId job,
+ enum edg_wll_RegJobJobtype type,
+ const char * jdl,
+ const char * ns,
+ edg_wlc_JobId parent,
+ int num_subjobs,
+ const char * seed,
+ edg_wlc_JobId ** subjobs)
+{
+ return edg_wll_RegisterJobMaster(context,0,job,type,jdl,ns, parent, num_subjobs,seed,subjobs);
+}
+
+int edg_wll_RegisterSubjobs(edg_wll_Context ctx,const edg_wlc_JobId parent,
+ char const * const * jdls, const char * ns, edg_wlc_JobId const * subjobs)
+{
+ char const * const *pjdl;
+ edg_wlc_JobId const *psubjob;
+ edg_wlc_JobId oldctxjob;
+ char * oldctxseq;
+
+ if (edg_wll_GetLoggingJob(ctx, &oldctxjob)) return edg_wll_Error(ctx, NULL, NULL);
+ oldctxseq = edg_wll_GetSequenceCode(ctx);
+
+ pjdl = jdls;
+ psubjob = subjobs;
+
+ while (*pjdl != NULL) {
+ if (edg_wll_RegisterSubjob(ctx, *psubjob, EDG_WLL_REGJOB_SIMPLE, *pjdl,
+ ns, parent, 0, NULL, NULL) != 0) break;
+ pjdl++; psubjob++;
+ }
+
+ edg_wll_SetLoggingJob(ctx, oldctxjob, oldctxseq, EDG_WLL_SEQ_NORMAL);
+
+ return edg_wll_Error(ctx, NULL, NULL);
+}
+
+int edg_wll_ChangeACL(
+ edg_wll_Context ctx,
+ const edg_wlc_JobId jobid,
+ const char *user_id,
+ enum edg_wll_UserIdType user_id_type,
+ enum edg_wll_Permission permission,
+ enum edg_wll_PermissionType permission_type,
+ enum edg_wll_ACLOperation operation)
+{
+ if ( edg_wll_SetLoggingJob(ctx, jobid, NULL, EDG_WLL_SEQ_NORMAL) == 0 )
+ edg_wll_LogEventMaster(ctx, 1, EDG_WLL_EVENT_CHANGEACL, EDG_WLL_FORMAT_CHANGEACL,
+ user_id, user_id_type, permission, permission_type, operation);
+
+
+ return edg_wll_Error(ctx,NULL,NULL);
+}
--- /dev/null
+#ident "$Header$"
+
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <getopt.h>
+#include <string.h>
+#include <time.h>
+#include <errno.h>
+
+#include <globus_common.h>
+
+#define CLIENT_SBIN_PROG
+
+#include "glite/wms/tls/ssl_helpers/ssl_inits.h"
+#include "glite/lb/consumer.h"
+#include "glite/lb/context-int.h"
+#include "glite/lb/purge.h"
+#include "glite/lb/xml_parse.h"
+#include "glite/lb/mini_http.h"
+
+
+#define dprintf(x) { if (debug) printf x; }
+
+#define free_jobs(jobs) { \
+ if (jobs) { \
+ int i; \
+ for ( i = 0; jobs[i]; i++ ) \
+ free(jobs[i]); \
+ free(jobs); \
+ } \
+}
+
+static const char rcsid[] = "@(#)$Id$";
+
+static int debug=0;
+static char *file;
+
+static int read_jobIds(const char *file, char ***jobs_out);
+static int get_timeout(const char *arg, int *timeout);
+static void printerr(edg_wll_Context ctx);
+
+static struct option opts[] = {
+ { "aborted", required_argument, NULL, 'a'},
+ { "cleared", required_argument, NULL, 'c'},
+ { "cancelled", required_argument, NULL, 'n'},
+ { "other", required_argument, NULL, 'o'},
+ { "dry-run", no_argument, NULL, 'r'},
+ { "jobs", required_argument, NULL, 'j'},
+ { "return-list", no_argument, NULL, 'l'},
+ { "server-dump", no_argument, NULL, 's'},
+ { "client-dump", no_argument, NULL, 'i'},
+ { "help", no_argument, NULL, 'h' },
+ { "version", no_argument, NULL, 'v' },
+ { "debug", no_argument, NULL, 'd' },
+ { "server", required_argument, NULL, 'm' },
+ { NULL, no_argument, NULL, 0 }
+};
+
+static void usage(char *me)
+{
+ fprintf(stderr,"usage: %s [option]\n"
+ " -a, --aborted NNN[smhd] purge ABORTED jobs older than NNN secs/mins/hours/days\n"
+ " -c, --cleared NNN[smhd] purge CLEARED jobs older than given time\n"
+ " -n, --cancelled NNN[smhd] purge CANCELLED jobs older than given time\n"
+ " -o, --other NNN[smhd] purge OTHER jobs older than given time\n"
+ " -r, --dry-run do not really purge\n"
+ " -j, --jobs <filename> input file with jobIds of jobs to purge\n"
+ " -l, --return-list return list of jobid matching the purge/dump criteria\n"
+ " -s, --server-dump dump jobs into any server file\n"
+ " -i, --client-dump receive stream of dumped jobs\n"
+ " -h, --help display this help\n"
+ " -v, --version display version\n"
+ " -d, --debug diagnostic output\n"
+ " -m, --server L&B server machine name\n",
+ me);
+}
+
+int main(int argc,char *argv[])
+{
+ edg_wll_PurgeRequest *request;
+ edg_wll_PurgeResult *result;
+ int i, timeout;
+ char *server = NULL;
+
+ char *me;
+ int opt;
+ edg_wll_Context ctx;
+
+ /* initialize request to server defaults */
+ request = (edg_wll_PurgeRequest *) calloc(1,sizeof(edg_wll_PurgeRequest));
+ request->jobs = NULL;
+ for (i=0; i < EDG_WLL_NUMBER_OF_STATCODES; i++) {
+ request->timeout[i]=-1;
+ }
+ request->flags = EDG_WLL_PURGE_REALLY_PURGE;
+
+ /* initialize result */
+ result = (edg_wll_PurgeResult *) calloc(1,sizeof(edg_wll_PurgeResult));
+
+ me = strrchr(argv[0],'/');
+ if (me) me++; else me=argv[0];
+
+ /* get arguments */
+ while ((opt = getopt_long(argc,argv,"a:c:n:o:j:m:rlsidhv",opts,NULL)) != EOF) {
+ timeout=-1;
+
+ switch (opt) {
+
+ case 'a':
+ if ((get_timeout(optarg,&timeout) != 0 )) {
+ printf("Wrong usage of timeout argument.\n");
+ usage(me);
+ return 1;
+ }
+ if (timeout >= 0) {
+ request->timeout[EDG_WLL_JOB_ABORTED]=timeout;
+ }
+ break;
+
+ case 'c':
+ if (get_timeout(optarg,&timeout) != 0 ) {
+ printf("Wrong usage of timeout argument.\n");
+ usage(me);
+ return 1;
+ }
+ if (timeout >= 0) {
+ request->timeout[EDG_WLL_JOB_CLEARED]=timeout;
+ }
+ break;
+
+ case 'n':
+ if (get_timeout(optarg,&timeout) != 0 ) {
+ printf("Wrong usage of timeout argument.\n");
+ usage(me);
+ return 1;
+ }
+ if (timeout >= 0) {
+ request->timeout[EDG_WLL_JOB_CANCELLED]=timeout;
+ }
+ break;
+ case 'o':
+ if (get_timeout(optarg,&timeout) != 0 ) {
+ printf("Wrong usage of timeout argument.\n");
+ usage(me);
+ return 1;
+ }
+ if (timeout >= 0) request->timeout[EDG_WLL_PURGE_JOBSTAT_OTHER]= timeout;
+ break;
+
+ case 'm': server = optarg; break;
+ case 'j': file = optarg; break;
+ case 'r': request->flags &= (~EDG_WLL_PURGE_REALLY_PURGE); break;
+ case 'l': request->flags |= EDG_WLL_PURGE_LIST_JOBS; break;
+ case 's': request->flags |= EDG_WLL_PURGE_SERVER_DUMP; break;
+ case 'i': request->flags |= EDG_WLL_PURGE_CLIENT_DUMP; break;
+ case 'd': debug = 1; break;
+ case 'v': fprintf(stdout,"%s:\t%s\n",me,rcsid); exit(0);
+ case 'h':
+ case '?': usage(me); return 1;
+ }
+ }
+
+ /* Initialize Globus common module */
+ dprintf(("Initializing Globus common module..."));
+ if (globus_module_activate(GLOBUS_COMMON_MODULE) != GLOBUS_SUCCESS) {
+ dprintf(("no.\n"));
+ fprintf(stderr,"Unable to initialize Globus common module\n");
+ } else {
+ dprintf(("yes.\n"));
+ }
+
+ edg_wlc_SSLInitialization();
+
+ /* initialize context */
+ edg_wll_InitContext(&ctx);
+
+ /* read the jobIds from file, if wanted */
+ if (file) {
+ char **jobs=NULL;
+ dprintf(("Reading jobIds form file \'%s\'...",file));
+ if (read_jobIds(file,&jobs) != 0) {
+ dprintf(("no.\n"));
+ fprintf(stderr,"Unable to read jobIds from file \'%s\'\n",file);
+ goto main_end;
+ } else {
+ dprintf(("yes.\n"));
+ }
+ request->jobs = jobs;
+ }
+
+ /* check request */
+ if (debug) {
+ printf("Purge request:\n");
+ printf("- flags: %d\n",request->flags);
+ printf("- %d timeouts:\n",EDG_WLL_NUMBER_OF_STATCODES);
+ for (i=0; i < EDG_WLL_NUMBER_OF_STATCODES; i++) {
+ char *stat=edg_wll_StatToString(i);
+ printf("\t%s: %ld\n",stat,request->timeout[i]);
+ if (stat) free(stat);
+ }
+ printf("- list of jobs:\n");
+ if (!request->jobs) {
+ printf("Not specified.\n");
+ } else {
+ for ( i = 0; request->jobs[i]; i++ )
+ printf("%s\n", request->jobs[i]);
+ }
+ }
+
+ if ( server )
+ {
+ char *p = strchr(server, ':');
+ if ( p )
+ {
+ edg_wll_SetParam(ctx, EDG_WLL_PARAM_QUERY_SERVER_PORT, atoi(p+1));
+ *p = 0;
+ }
+ edg_wll_SetParam(ctx, EDG_WLL_PARAM_QUERY_SERVER, server);
+ }
+
+ /* that is the Purge */
+ dprintf(("Running the edg_wll_Purge...\n"));
+ if (edg_wll_Purge(ctx, request, result) != 0) {
+ fprintf(stderr,"Error running the edg_wll_Purge().\n");
+ printerr(ctx);
+ switch ( edg_wll_Error(ctx, NULL, NULL) )
+ {
+ case ENOENT:
+ case EPERM:
+ case EINVAL:
+ break;
+ default:
+ goto main_end;
+ }
+ }
+
+ /* examine the result */
+ dprintf(("Examining the result of edg_wll_Purge...\n"));
+ if (result->server_file) {
+ printf("Server dump: %s\n",result->server_file);
+ } else {
+ printf("The jobs were not dumped.\n");
+ }
+ if (request->flags & EDG_WLL_PURGE_LIST_JOBS) {
+ printf("The following jobs %s purged:\n",
+ request->flags & EDG_WLL_PURGE_REALLY_PURGE ? "were" : "would be");
+ if (!result->jobs) printf("None.\n");
+ else {
+ int i;
+ for ( i = 0; result->jobs[i]; i++ )
+ printf("%s\n",result->jobs[i]);
+ }
+ }
+
+main_end:
+ dprintf(("End.\n"));
+ if (request)
+ {
+ free_jobs(request->jobs);
+ free(request);
+ }
+ if (result) free(result);
+ edg_wll_FreeContext(ctx);
+ return 0;
+}
+
+
+static void printerr(edg_wll_Context ctx)
+{
+ char *errt,*errd;
+
+ edg_wll_Error(ctx,&errt,&errd);
+ fprintf(stderr,"%s (%s)\n",errt,errd);
+}
+
+
+static int read_jobIds(const char *file, char ***jobs_out)
+{
+ FILE *jobIds = fopen(file,"r");
+ char buf[256];
+ char **jobs;
+ int cnt = 0;
+
+ jobs = NULL;
+
+
+ if (!jobIds) {
+ perror(file);
+ return 1;
+ }
+
+ while ( 1 ) {
+ char *nl;
+ if ( !fgets(buf,sizeof buf,jobIds) )
+ {
+ if (feof(jobIds))
+ break;
+
+ free_jobs(jobs);
+ fprintf(stderr, "Error reading file\n");
+ return 1;
+ }
+ nl = strchr(buf,'\n');
+ if (nl) *nl = 0;
+ /* TODO: check if it is really jobId, e.g. by edg_wlc_JobIdParse() */
+
+ if ( !(jobs = realloc(jobs, (cnt+2)*sizeof(*jobs))) )
+ {
+ perror("cond_parse()");
+ return(1);
+ }
+ jobs[cnt++] = strdup(buf);
+ }
+ jobs[cnt] = NULL;
+
+ fclose(jobIds);
+ *jobs_out = jobs;
+
+ return 0;
+}
+
+static int get_timeout(const char *arg, int *timeout)
+{
+ int t = -1;
+ char tunit = '\0';
+
+ if (sscanf(arg,"%d%c",&t,&tunit) > 0) {
+ if (tunit) {
+ switch (tunit) {
+ case 'd': t *= 86400; break; // 24*60*60
+ case 'h': t *= 3600; break; // 60*60
+ case 'm': t *= 60; break;
+ case 's': break;
+ default: fprintf(stderr,"Allowed time units are s,m,h,d\n");
+ return -1;
+ }
+ }
+ }
+ if (t < 0) return -1;
+ *timeout = t;
+ return 0;
+}
+
+static const char* const request_headers[] = {
+ "Cache-Control: no-cache",
+ "Accept: application/x-dglb",
+ "User-Agent: edg_wll_Api/" PROTO_VERSION "/" COMP_PROTO,
+ "Content-Type: application/x-dglb",
+ NULL
+};
+
+int edg_wll_Purge(
+ edg_wll_Context ctx,
+ edg_wll_PurgeRequest *request,
+ edg_wll_PurgeResult *result)
+{
+ char *send_mess,
+ *response = NULL,
+ *recv_mess = NULL;
+
+ edg_wll_ResetError(ctx);
+
+ if (request->flags & EDG_WLL_PURGE_CLIENT_DUMP)
+ return edg_wll_SetError(ctx,ENOSYS,"client dump");
+
+ if (edg_wll_PurgeRequestToXML(ctx, request, &send_mess))
+ goto edg_wll_purge_end;
+
+ //edg_wll_SetParam(ctx, EDG_WLL_PARAM_QUERY_TIMEOUT, 4000);
+ ctx->p_tmp_timeout.tv_sec = 400;
+
+ if (set_server_name_and_port(ctx, NULL))
+ goto edg_wll_purge_end;
+
+ if (edg_wll_http_send_recv(ctx,
+ "POST /purgeRequest HTTP/1.1", request_headers, send_mess,
+ &response, NULL, &recv_mess))
+ goto edg_wll_purge_end;
+
+ if (http_check_status(ctx, response, &recv_mess))
+ goto edg_wll_purge_end;
+
+ if (edg_wll_ParsePurgeResult(ctx, recv_mess, result))
+ goto edg_wll_purge_end;
+
+edg_wll_purge_end:
+ if (response) free(response);
+ if (recv_mess) free(recv_mess);
+ if (send_mess) free(send_mess);
+ return edg_wll_Error(ctx,NULL,NULL);
+}
--- /dev/null
+#ident "$Header$"
+/*
+@@@AUTO
+*/
+@@@LANG: C
+
+#include "glite/wms/jobid/cjobid.h"
+#include "glite/lb/producer.h"
+
+@@@{
+for my $t (sort { $event->{order}->{$a} <=> $event->{order}->{$b} }
+ $event->getTypes) {
+ my $tu = uc $t;
+ my $a = "(edg_wll_Context context";
+ my $b = "(context,EDG_WLL_EVENT_$tu,EDG_WLL_FORMAT_$tu";
+ my $decl = "";
+ my $free = "";
+ my $doc = qq{
+ * \\param context\tcontext to work with,
+};
+ selectType $event $t;
+ for ($event->getFieldsOrdered) {
+ my $f = selectField $event $_;
+ my $fn = $f->getName;
+ my $ft;
+ my $bfn = $fn;
+ if ($f->{codes}) {
+# $ft = "enum edg_wll\_$t" . ucfirst $fn;
+ $ft = "char *";
+ } else {
+ $ft = $f->getType;
+ }
+ if ($ULMasString{$f->{type}}) {
+ $decl .= "\tchar *s_$fn = ".$f->getType()."ToString($fn);\n";
+ $free .= "\tfree(s_$fn);\n";
+ $bfn = "s_$fn";
+ }
+ $ft = "const ".$ft;
+ my $fc = $f->getComment;
+ $a = $a . ", $ft $fn";
+ $b = $b . ", $bfn";
+ $doc = $doc . " * \\param $fn\t$fc\n";
+ }
+ $a = $a . ")";
+ $b = $b . ")";
+
+ gen qq{
+/*!
+ * \\fn int edg_wll_Log$t$a;
+ * \\brief simple wrapper around edg_wll_LogEvent for event $t} . $doc . qq{ * \\see edg_wll_LogEvent\(\)
+ */
+};
+# gen "\nextern int edg_wll_Log$t$a;\n\n";
+ gen qq{
+int edg_wll_Log$t$a
+\{
+$decl
+ return edg_wll_LogEvent$b;
+\}\n
+};
+ for ($event->getFieldsOrdered) {
+ my $f = selectField $event $_;
+ my $fn = $f->getName;
+ my $ft;
+ if ($f->{codes}) {
+# $ft = "enum edg_wll\_$t" . ucfirst $fn;
+ $ft = "char *";
+ } else {
+ $ft = $f->getType;
+ }
+ my $ftreg = $ft;
+ $ftreg =~ s/\*/\\\*/g;
+ $ftreg = "const ".$ftreg;
+ my $fc = $f->getComment;
+ if ($f->{codes}) {
+ for (@{$f->{codes}}) {
+ my $code = uc $_->{name};
+ my $c = $a;
+ my $d = $b;
+ my $e = $doc;
+ $c =~ s/, $ftreg $fn//g;
+ $d =~ s/$fn/"$code"/g;
+ $e =~ s/ \* \\param $fn\t$fc\n//g;
+ gen qq{
+/*!
+ * \\fn int edg_wll_Log$t$code$c;
+ * \\brief simple wrapper around edg_wll_LogEvent for event $t, $fn $code} . $e . qq{ * \\see edg_wll_LogEvent\(\)
+ */
+};
+# gen "\nextern int edg_wll_Log$t$code$c;\n\n";
+ gen qq{
+int edg_wll_Log$t$code$c
+\{
+$decl;
+ return edg_wll_LogEvent$d;
+\}\n
+};
+ }
+ }
+ }
+}
+@@@}
--- /dev/null
+include Makefile.inc
+
+
+VPATH:=${src}
+AT3:=perl -I${lbconfig} ${lbproject}/at3
+
+SUFFIXES = .T
+
+DEBUG:=-g -O0
+CFLAGS:=${DEBUG} -I${src} -I${repository}/${globus}/include/${globusflavour} \
+ -I${repository}/${globus}/include/${globusflavour}/openssl \
+ -I${repository}/${ares}/include -I${repository}/${expat}/include\
+ -I${stageinc} -I${interface} \
+ -DDATAGRID_EXTENSION
+
+LDFLAGS:=-L${stagelib}
+
+COMPILE:=libtool --mode=compile ${CC} ${CFLAGS}
+LINK:=libtool --mode=link ${CC} -rpath ${stagelib} ${LDFLAGS}
+INSTALL:=libtool --mode=install install
+
+OBJS:=dgssl.o escape.o events.o mini_http.o query_rec.o status.o \
+ xml_conversions.o xml_parse.o ulm_parse.o param.o \
+ events_parse.o il_string.o il_int.o notifid.o \
+ il_log.o il_msg.o context.o trio.o strio.o
+LOBJS:=`echo ${OBJS} | sed 's/\.o/\.lo/g'`
+
+HDRS:=context-int.h dgssl.h mini_http.h authz.h xml_parse.h \
+ xml_conversions.h log_proto.h events_parse.h il_string.h escape.h \
+ ulm_parse.h trio.h
+
+STATICLIB:=libglite_lb_common.a
+LTLIB:=libglite_lb_common.la
+
+default: all
+
+compile: ${STATICLIB} ${LTLIB}
+
+${STATICLIB}: ${OBJS}
+ ar crv $@ ${OBJS}
+ ranlib $@
+
+${LTLIB}: ${OBJS}
+ ${LINK} -o $@ ${LOBJS} \
+ -L${stagelib} -lglobus_ssl_utils -lglite_wms_cjobid \
+ -lm
+
+stage export all: compile
+ ${INSTALL} -m 644 ${STATICLIB} ${stagelib}
+ ${INSTALL} -m 644 ${LTLIB} ${stagelib}
+ cd ${interface} && install -m 644 ${HDRS} ${stageinc}/${globalprefix}/${lbprefix}
+
+
+check:
+ echo Unit tests missing
+
+%.o: %.c
+ ${COMPILE} -c $<
+
+
+%.h: %.h.T
+ rm -f $@
+ ${AT3} $< >$@ || rm -f $@
+ chmod -w $@ >/dev/null
+
+%.c: %.c.T
+ rm -f $@
+ ${AT3} $< >$@ || rm -f $@
+ chmod -w $@ >/dev/null
--- /dev/null
+<?xml version="1.0" encoding="UTF-8" ?>
+
+<project name="lb" default="dist">
+
+ <import file="../org.glite/project/baseline.properties.xml" />
+ <import file="./project/properties.xml"/>
+ <import file="${subsystem.properties.file}"/>
+ <import file="${global.properties.file}" />
+
+ <property file="${user.dependencies.file}"/>
+ <property file="${component.dependencies.file}" />
+ <property file="${subsystem.dependencies.file}" />
+ <property file="${global.dependencies.file}"/>
+
+ <import file="${subsystem.taskdefs.file}" />
+ <import file="${global.taskdefs.file}" />
+
+ <import file="${global.targets-external-dependencies.file}"/>
+ <import file="${global.targets-make.file}" />
+
+ <property file="${module.version.file}"/>
+
+ <target name="localinit"
+ description="Module specific initialization tasks">
+ <antcall target="lbmakefiles"/>
+ </target>
+
+ <target name="localcompile"
+ description="Module specific compile tasks">
+ </target>
+
+ <target name="localclean"
+ description="Module specific cleaning tasks">
+ </target>
+
+</project>
--- /dev/null
+#ifndef _LB_AUTHZ_H
+#define _LB_AUTHZ_H
+
+#ident "$Header$"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct _edg_wll_VomsGroup {
+ char *vo;
+ char *name;
+} edg_wll_VomsGroup;
+
+typedef struct _edg_wll_VomsGroups {
+ size_t len;
+ edg_wll_VomsGroup *val;
+} edg_wll_VomsGroups;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
--- /dev/null
+#ifndef __EDG_WORKLOAD_LOGGING_COMMON_CONTEXT_H__
+#define __EDG_WORKLOAD_LOGGING_COMMON_CONTEXT_H__
+
+#ident "$Header$"
+
+#include "glite/lb/consumer.h"
+#include "dgssl.h"
+#include "authz.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+typedef struct _edg_wll_SeqCode {
+ unsigned int c[EDG_WLL_SOURCE__LAST];
+} edg_wll_SeqCode;
+
+
+
+typedef struct _edg_wll_ConnPool {
+/* address and port where we are connected to */
+ char *peerName;
+ unsigned int peerPort;
+
+/* http(s) stream */
+ void *gsiCred;
+ SSL *ssl;
+ char *buf;
+ int bufUse,bufSize;
+
+/* timestamp of usage of this entry in ctx.connPool */
+ struct timeval lastUsed;
+} edg_wll_ConnPool;
+
+
+
+struct _edg_wll_Context {
+/* Error handling */
+ int errCode; /* recent error code */
+ char *errDesc; /* additional error description */
+
+/* server part */
+
+ void *mysql;
+ edg_wll_ConnPool *connPool;
+
+ int semaphores,semset;
+ edg_wll_QueryRec **job_index;
+ void *job_index_cols;
+
+ time_t peerProxyValidity;
+ char *peerName;
+ edg_wll_VomsGroups vomsGroups;
+ int allowAnonymous;
+ int noAuth; /* if set, you can obtain info about events */
+ /* and jobs not belonging to you */
+ int noIndex; /* don't enforce indices */
+ int rgma_export;
+ int strict_locking; /* lock jobs for storing event too */
+
+
+/* server limits */
+ int softLimit;
+ int hardJobsLimit;
+ int hardEventsLimit;
+
+ time_t notifDuration;
+
+/* purge and dump files storage */
+ char *dumpStorage;
+ char *purgeStorage;
+
+/* flag for function store_event
+ * if set then event are loaded from dump file
+ */
+ int event_load;
+
+/* address and port we are listening at */
+ char *srvName;
+ unsigned int srvPort;
+
+/* pool of connections from client */
+ int poolSize;
+ int connOpened; /* number of opened connections */
+ int connToUse; /* index of connection that will *
+ * be used by low-level f-cions */
+/* other client stuff */
+ int notifSock; /* default client socket *
+ * for receiving notifications */
+
+/* user settable parameters */
+ char *p_host;
+ edg_wll_Source p_source;
+ char *p_instance;
+ enum edg_wll_Level p_level;
+ char *p_destination;
+ int p_dest_port;
+ struct timeval p_log_timeout,p_sync_timeout,p_query_timeout, p_notif_timeout, p_tmp_timeout;
+ char *p_query_server;
+ int p_query_server_port;
+ int p_query_server_override;
+ int p_query_events_limit;
+ int p_query_jobs_limit;
+ edg_wll_QueryResults p_query_results;
+ char *p_notif_server;
+ int p_notif_server_port;
+ char *p_proxy_filename;
+ char *p_cert_filename;
+ char *p_key_filename;
+ time_t purge_timeout[EDG_WLL_NUMBER_OF_STATCODES];
+/* producer part */
+ edg_wlc_JobId p_jobid;
+ edg_wll_SeqCode p_seqcode;
+};
+
+/* to be used internally: set, update and and clear the error information in
+ * context, the desc string (if provided) is strdup()-ed
+ *
+ * all return the error code for convenience (usage in return statement) */
+
+
+extern int edg_wll_SetError(
+ edg_wll_Context, /* context */
+ int, /* error code */
+ const char * /* error description */
+);
+
+/** update errDesc and errCode */
+extern int edg_wll_UpdateError(
+ edg_wll_Context, /* context */
+ int, /* error code */
+ const char * /* error description */
+);
+
+/** set errCode to 0, free errDesc */
+extern int edg_wll_ResetError(edg_wll_Context);
+
+/** retrieve standard error text wrt. code
+ * !! does not allocate memory */
+extern const char *edg_wll_GetErrorText(int);
+
+extern int edg_wll_ContextReopen(edg_wll_Context);
+
+extern int edg_wll_SetSequenceCode(edg_wll_Context, const char *, int);
+extern int edg_wll_IncSequenceCode(edg_wll_Context ctx);
+
+
+#ifdef __cplusplus
+}
+#endif
+#endif /* __EDG_WORKLOAD_LOGGING_COMMON_CONTEXT_H__ */
--- /dev/null
+#ifndef __EDG_WORKLOAD_LOGGING_COMMON_DGSSL_H__
+#define __EDG_WORKLOAD_LOGGING_COMMON_DGSSL_H__
+/**
+ * \file Client/dgssl.h
+ * \brief Auxiliary SSL functions for L&B
+ */
+
+#ident "$Header$"
+
+/* openssl headers */
+#include <globus_config.h>
+#include "glite/wms/thirdparty/globus_ssl_utils/sslutils.h"
+
+#include <ssl.h>
+#include <err.h>
+#include <rand.h>
+#include <bio.h>
+#include <pem.h>
+#include <x509.h>
+#if SSLEAY_VERSION_NUMBER >= 0x0090581fL
+#include <x509v3.h>
+#endif
+
+/**
+ * Initialize SSL and GSI contexts and set SSL parameters for authentication.
+ * \param verify IN: specifies SSL authentication mode to be used for peer
+ * verification. (SSL_VERIFY_NONE, SSL_VERIFY_PEER,
+ * SSL_VERIFY_FAIL_IF_NO_PEER_CERT, SSL_VERIFY_CLIENT_ONCE) -- see also ssl.h
+ * \param callback IN: if nonzero the standard GSI authentication callback will
+ * be called on each certificate in a chain in order to verify the chain
+ * consists only of valid GSI proxy certs. If the parametr is zero only the
+ * default SSL callback will be used.
+ * \param p_cert_file IN: file containg the caller's cert.
+ * \param p_key_file IN: file containg the caller's key. If at least one of
+ * these parameters is NULL, the default proxy is examined and used (if
+ * exists), otherwise the default long-term credential will be used. \param
+ * ask_passwd IN: if nonzero, the standard SSL prompt is used whenever an
+ * encrypted keyfile is encountered. If the paramater zero, no password will be
+ * prompted for even if the key is encrypted.
+ * \param no_auth IN: if nonzero, only context necessary for authentication of
+ * the peer will be set. No caller's credential is read.
+ * \retval pointer to an opaque structure containg the initialized context, if
+ * any error occurs, the context will contain only those basic parameters
+ * necessary for authentication of the peer
+ */
+proxy_cred_desc *edg_wll_ssl_init(int verify, int callback, char *p_cert_file,char *p_key_file,
+ int ask_passwd, int noauth);
+
+/**
+ * frees cred_handle returned by edg_wll_ssl_init()
+ * \param cred_handle IN: pointer returned by edg_wll_ssl_init()
+ */
+int edg_wll_ssl_free(proxy_cred_desc *cred_handle);
+
+/**
+ * Establish SSL context with server.
+ * Called by the clients when they tryies to do SSL handshake with the server.
+ * This includes authentication of the server and optionaly the client, and
+ * establishing SSL security parameters.
+ *
+ * \param cred_handle IN: pointer returned by edg_wll_ssl_init()
+ * \param hostname IN: hostname to connect to
+ * \param port IN: port to connect to
+ * \param timeout INOUT: if NULL, blocking SSL I/O is done, otherwise the
+ * I/O and SSL handshake will take at most the specified time. Remaining
+ * time is returned.
+ * \param sslp OUT: on success, returned pointer to SSL connection
+ * \return one of EDG_WLL_SSL_*
+ */
+int edg_wll_ssl_connect(proxy_cred_desc *cred_handle,char const *hostname,int port,
+ struct timeval *timeout,SSL **sslp);
+
+/**
+ * Establish SSL context with client.
+ * Called by the server when trying to do a SSL handshake with the client. A
+ * network connection must be established before calling this function. Use
+ * timeout set in context.
+ * \param ctx IN: used to obtain timeout
+ * \param cred_handle IN: pointer returned by edg_wll_ssl_init()
+ * \param sock IN: specification of the network connection
+ * \retval pointer to SSL connection on success
+ * \retval NULL on error
+ */
+SSL *edg_wll_ssl_accept(proxy_cred_desc *cred_handle,int sock, struct timeval *timeout);
+
+/**
+ * Try to send SSL close alert on socket (reject the client in orderly way).
+ * \param cred_handle IN: pointer returned by edg_wll_ssl_init(), to get SSL_CTX
+ * \param sock IN: specification of the network connection
+ */
+
+void edg_wll_ssl_reject(proxy_cred_desc *cred_handle,int sock);
+
+/**
+ * Close SSL connection, possibly saving open sessions, and destroy the SSL object.
+ * Called by anyone who wishes to close the connection.
+ * \param ssl IN: object identifying the SSL connection
+ * \param timeout INOUT: max time allowed for operation, remaining time
+ * on return
+ * \retval one of EDG_WLL_SSL_*
+ */
+int edg_wll_ssl_close_timeout(SSL *ssl, struct timeval *timeout);
+
+/**
+ * Close SSL connection, call edg_wll_ssl_close_timeout() with hard-wired
+ * timeout 120 secs.
+ * \param ssl IN: object identifying the SSL connection
+ * \retval one of EDG_WLL_SSL_*
+ */
+int edg_wll_ssl_close(SSL *ssl);
+
+/**
+ * Return subject name of the caller as specified in the context.
+ * \param cred_handle IN: pointer returned by edg_wll_ssl_init()
+ * \param my_subject_name OUT: contains the subject name. The caller must free
+ * this variable when no needed.
+ */
+void edg_wll_ssl_get_my_subject(proxy_cred_desc *cred_handle, char **my_subject_name);
+void edg_wll_ssl_get_my_subject_base(proxy_cred_desc *cred_handle, char **my_subject_name);
+
+/** no SSL errors */
+#define EDG_WLL_SSL_OK 0
+/** SSL specific error. Call ERR_* functions for details. */
+#define EDG_WLL_SSL_ERROR_SSL -1
+/** Timeout */
+#define EDG_WLL_SSL_ERROR_TIMEOUT -2
+/** EOF occured */
+#define EDG_WLL_SSL_ERROR_EOF -3
+/** System error. See errno. */
+#define EDG_WLL_SSL_ERROR_ERRNO -4
+/** Resolver error. See h_errno. */
+#define EDG_WLL_SSL_ERROR_HERRNO -5
+
+/**
+ * Read from SSL connection.
+ * Needn't read entire buffer. Timeout is applicable only for non-blocking
+ * connections (created with non-NULL timeout param of edg_wll_ssl_connect()).
+ * \param ssl IN: connection to work with
+ * \param buf OUT: buffer
+ * \param bufsize IN: max size to read
+ * \param timeout INOUT: max time allowed for operation, remaining time
+ * on return
+ * \retval bytes read (>0) on success
+ * \retval one of EDG_WLL_SSL_* (<0) on error
+ */
+
+int edg_wll_ssl_read(SSL *ssl,void *buf,size_t bufsize,struct timeval *timeout);
+
+/**
+ * Write to SSL connection.
+ * Needn't write entire buffer. Timeout is applicable only for non-blocking
+ * connections (created with non-NULL timeout param of edg_wll_ssl_connect()).
+ * \param ssl IN: connection to work with
+ * \param buf IN: buffer
+ * \param bufsize IN: max size to write
+ * \param timeout INOUT: max time allowed for operation, remaining time
+ * on return
+ * \retval bytes written (>0) on success
+ * \retval one of EDG_WLL_SSL_* (<0) on error
+ */
+
+int edg_wll_ssl_write(SSL *ssl,const void *buf,size_t bufsize,struct timeval *timeout);
+
+/**
+ * Read specified amount of data from SSL connection.
+ * Attempts to call edg_wll_ssl_read() untill the entire request is satisfied
+ * (or EOF reached, or times out)
+ *
+ * \param ssl IN: connection to work with
+ * \param buf OUT: buffer
+ * \param bufsize IN: max size to read
+ * \param timeout INOUT: max time allowed for operation, remaining time
+ * on return
+ * \param total OUT: bytes actually read
+ * \return one of EDG_WLL_SSL_*
+ */
+
+int edg_wll_ssl_read_full(SSL *ssl,void *buf,size_t bufsize,struct timeval *timeout,size_t *total);
+
+/**
+ * Write specified amount of data to SSL connection.
+ * Attempts to call edg_wll_ssl_write() untill the entire request is satisfied
+ * (or times out).
+ *
+ * \param ssl IN: connection to work with
+ * \param buf IN: buffer
+ * \param bufsize IN: max size to read
+ * \param timeout INOUT: max time allowed for operation, remaining time
+ * on return
+ * \param total OUT: bytes actually written
+ * \return one of EDG_WLL_SSL_*
+ */
+
+int edg_wll_ssl_write_full(SSL *ssl,const void *buf,size_t bufsize,struct timeval *timeout,size_t *total);
+
+void edg_wll_ssl_set_noauth(proxy_cred_desc* cred_handle);
+
+/**
+ * Check modification times of key and cert files.
+ */
+int edg_wll_ssl_watch_creds(const char *,const char *,time_t *,time_t *);
+
+#endif /* __EDG_WORKLOAD_LOGGING_COMMON_DGSSL_H__ */
+
--- /dev/null
+#ifndef __EDG_WORKLOAD_LOGGING_COMMON_ESCAPE_H__
+#define __EDG_WORKLOAD_LOGGING_COMMON_ESCAPE_H__
+/*!
+ * \file Client/escape.h
+ * \brief Prototypes for Client/escape.c
+ */
+
+#ident "$Header$"
+
+
+/*!
+ * \fn char *edg_wll_LogEscape(const char *str)
+ * \param str a string to escape
+ * \return new (allocated) escaped string
+ * \brief in given string (ULM) escape all ULM_QM, ULM_BS and ULM_LF by ULM_BS
+ */
+
+char *edg_wll_LogEscape(const char *);
+
+
+/*!
+ * \fn char *edg_wll_LogUnescape(const char *str)
+ * \param str a string to unescape
+ * \return new (allocated) unescaped string
+ * \brief in given string (ULM) unescape all escaped ULM_QM, ULM_BS and ULM_LF
+ */
+
+char *edg_wll_LogUnescape(const char *);
+
+
+/*!
+ * \fn char *edg_wll_EscapeXML(const char *str);
+ * \param str a string to escape
+ * \return new (allocated) escaped string
+ * \brief in given string (XML) escape all unwanted characters
+ */
+
+char *edg_wll_EscapeXML(const char *);
+
+
+/*!
+ * \fn char *edg_wll_UnescapeXML(const char *str)
+ * \param str a string to unescape
+ * \return new (allocated) unescaped string
+ * \brief in given string (XML) unescape all escaped characters
+ */
+
+char *edg_wll_UnescapeXML(const char *);
+
+
+/*!
+ * \fn char *edg_wll_EscapeSQL(const char *str)
+ * \param str a string to escape
+ * \return new (allocated) escaped string
+ * \briefin given string (SQL) escape all unwanted characters
+ */
+
+char *edg_wll_EscapeSQL(const char *);
+
+#endif /* __EDG_WORKLOAD_LOGGING_COMMON_ESCAPE_H__ */
--- /dev/null
+#ifndef __EDG_WORKLOAD_LOGGING_COMMON_EVENTS_PARSE_H__
+#define __EDG_WORKLOAD_LOGGING_COMMON_EVENTS_PARSE_H__
+
+#ident "$Header$"
+
+#include "glite/lb/events.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+/**
+ * Parse a ULM line into a edg_wll_Event structure
+ * \param context IN: context to work with
+ * \param logline IN: ULM string to parse
+ * \param event OUT: parsed event
+ * (may be NULL - syntax checking with no output)
+ */
+extern edg_wll_ErrorCode edg_wll_ParseEvent(
+ edg_wll_Context context,
+ edg_wll_LogLine logline,
+ edg_wll_Event ** event
+);
+
+/**
+ * Generate ULM line from edg_wll_Event structure
+ * \param context IN: context to work with
+ * \param event IN: event to unparse
+ */
+extern edg_wll_LogLine edg_wll_UnparseEvent(
+ edg_wll_Context context,
+ edg_wll_Event * event
+);
+
+/**
+ * Check event for completness.
+ * Auxiliary function, checks whether all required fields of
+ * the event type are present.
+ * \param context IN: context to work with
+ * \param event IN: event to check
+ */
+extern edg_wll_ErrorCode edg_wll_CheckEvent(
+ edg_wll_Context context,
+ edg_wll_Event * event
+);
+
+/**
+ * Parse "only" jobId from ULM message
+ * \param logline IN: ULM string to parse
+ * \return jobId string
+ */
+extern char *edg_wll_GetJobId(edg_wll_LogLine logline);
+
+/**
+ * Parse a special Notification ULM line into a edg_wll_Event structure
+ * \param context IN: context to work with
+ * \param logline IN: ULM string to parse
+ * \param event OUT: parsed event
+ * (may be NULL - syntax checking with no output)
+ */
+extern edg_wll_ErrorCode edg_wll_ParseNotifEvent(
+ edg_wll_Context context,
+ edg_wll_LogLine logline,
+ edg_wll_Event ** event
+);
+
+/**
+ * Generate a special Notification ULM line from edg_wll_Event structure
+ * \param context IN: context to work with
+ * \param event IN: event to unparse
+ */
+extern edg_wll_LogLine edg_wll_UnparseNotifEvent(
+ edg_wll_Context context,
+ edg_wll_Event * event
+);
+
+#ifdef __cplusplus
+}
+#endif
+
+
+#endif /* __EDG_WORKLOAD_LOGGING_COMMON_EVENTS_PARSE_H__ */
--- /dev/null
+#ifndef NET_STRING_H
+#define NET_STRING_H
+
+#ident "$Header$"
+
+#define MAXLEN 1024
+
+char *put_int(char *p, int d);
+char *_put_int(char *p, int d);
+char *put_string(char *p, char *s);
+
+char *get_int(char *p, int *d);
+char *_get_int(char *p, int *d);
+char *get_string(char *p, char **s);
+
+int len_string(char *s);
+int len_int(int d);
+
+enum {
+ LB_OK = 0,
+ LB_NOMEM = 200,
+ LB_PROTO = 400,
+ LB_AUTH = 500,
+ LB_PERM = 600,
+ LB_DBERR = 700,
+ LB_SYS = 800,
+ LB_TIME = 900
+};
+
+#endif
--- /dev/null
+#ifndef __EDG_WORKLOAD_LOGGING_COMMON_LOG_PROTO_H__
+#define __EDG_WORKLOAD_LOGGING_COMMON_LOG_PROTO_H__
+
+#ident "$Header$"
+
+/**
+ * \file edg/workload/logging/common/log_proto.h
+ * \brief common part of the logging protocol
+ * \note private
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+/**
+ * default (noauth) user name
+ */
+/** default user */
+#define EDG_WLL_LOG_USER_DEFAULT "anonymous"
+
+
+/**
+ * default prefix for names of log files
+ */
+/** default prefix */
+#define EDG_WLL_LOG_PREFIX_DEFAULT "/tmp/dglogd.log"
+
+
+/**
+ * default local-logger Socket header
+ */
+/** header text */
+#define EDG_WLL_LOG_SOCKET_HEADER "DGLOG"
+/** header length */
+#define EDG_WLL_LOG_SOCKET_HEADER_LENGTH 5
+
+
+/**
+ * default local-logger destination
+ */
+/** host */
+#define EDG_WLL_LOG_HOST_DEFAULT "localhost"
+/** port */
+#define EDG_WLL_LOG_PORT_DEFAULT 9002
+
+
+/**
+ * default and maximal logging timeout (in seconds)
+ */
+#define EDG_WLL_LOG_TIMEOUT_DEFAULT 120
+#define EDG_WLL_LOG_TIMEOUT_MAX 1800
+#define EDG_WLL_LOG_SYNC_TIMEOUT_DEFAULT 120
+#define EDG_WLL_LOG_SYNC_TIMEOUT_MAX 1800
+
+
+/**
+ * maximal message size for sync logging
+ */
+/** max message size in bytes */
+// unlimited for tests!
+#define EDG_WLL_LOG_SYNC_MAXMSGSIZE 102400000
+
+
+/**
+ * default maximal number of simultaneously open connections from one client
+ */
+#define EDG_WLL_LOG_CONNECTIONS_DEFAULT 4
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __EDG_WORKLOAD_LOGGING_COMMON_LOG_PROTO_H__ */
--- /dev/null
+#ifndef __EDG_WORKLOAD_LOGGING_COMMON_MINI_HTTP_H__
+#define __EDG_WORKLOAD_LOGGING_COMMON_MINI_HTTP_H__
+
+#ident "$Header$"
+
+#include "glite/lb/consumer.h"
+
+/* XXX: not a good place for the folowing #def's but we ain't got better currently */
+/** protocol version */
+#define PROTO_VERSION "3.0"
+/** backward protocol compatibility */
+/* version separated by comma */
+/* e.g. "1.0,1.2,1.3" */
+#define COMP_PROTO "3.0"
+
+
+/* subset of HTTP codes we return */
+#define HTTP_OK 200
+#define HTTP_BADREQ 400
+#define HTTP_UNAUTH 401
+#define HTTP_NOTFOUND 404
+#define HTTP_NOTALLOWED 405
+#define HTTP_UNSUPPORTED 415
+#define HTTP_INTERNAL 500
+#define HTTP_NOTIMPL 501
+#define HTTP_UNAVAIL 503
+#define HTTP_INVALID 579
+
+extern edg_wll_ErrorCode edg_wll_http_recv(
+ edg_wll_Context, /* INOUT: context */
+ char **, /* OUT: first line */
+ char ***, /* OUT: null terminated array of headers */
+ char ** /* OUT: message body */
+);
+
+extern edg_wll_ErrorCode edg_wll_http_send(
+ edg_wll_Context, /* INOUT: context */
+ const char *, /* IN: first line */
+ char const * const *, /* IN: headers */
+ const char * /* IN: message body */
+);
+
+#endif /* __EDG_WORKLOAD_LOGGING_COMMON_MINI_HTTP_H__ */
--- /dev/null
+/*************************************************************************
+ *
+ * $Id$
+ *
+ * Copyright (C) 1998 Bjorn Reese and Daniel Stenberg.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
+ * MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE AUTHORS AND
+ * CONTRIBUTORS ACCEPT NO RESPONSIBILITY IN ANY CONCEIVABLE MANNER.
+ *
+ ************************************************************************/
+
+#ifndef TRIO_TRIO_H
+#define TRIO_TRIO_H
+
+#include <stdio.h>
+#include <stdarg.h>
+#include <stdlib.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* make utility and C++ compiler in Windows NT fails to find this symbol */
+#if defined(WIN32) && !defined(isascii)
+# define isascii ((unsigned)(x) < 0x80)
+#endif
+
+/*
+ * Error codes.
+ *
+ * Remember to add a textual description to trio_strerror.
+ */
+enum {
+ TRIO_EOF = 1,
+ TRIO_EINVAL = 2,
+ TRIO_ETOOMANY = 3,
+ TRIO_EDBLREF = 4,
+ TRIO_EGAP = 5,
+ TRIO_ENOMEM = 6,
+ TRIO_ERANGE = 7
+};
+
+/* Error macros */
+#define TRIO_ERROR_CODE(x) ((-(x)) & 0x00FF)
+#define TRIO_ERROR_POSITION(x) ((-(x)) >> 8)
+#define TRIO_ERROR_NAME(x) trio_strerror(x)
+
+const char *trio_strerror(int);
+
+/*************************************************************************
+ * Print Functions
+ */
+
+int trio_printf(const char *format, ...);
+int trio_vprintf(const char *format, va_list args);
+int trio_printfv(const char *format, void **args);
+
+int trio_fprintf(FILE *file, const char *format, ...);
+int trio_vfprintf(FILE *file, const char *format, va_list args);
+int trio_fprintfv(FILE *file, const char *format, void **args);
+
+int trio_dprintf(int fd, const char *format, ...);
+int trio_vdprintf(int fd, const char *format, va_list args);
+int trio_dprintfv(int fd, const char *format, void **args);
+
+/* trio_sprintf(target, format, ...)
+ * trio_snprintf(target, maxsize, format, ...)
+ *
+ * Build 'target' according to 'format' and succesive
+ * arguments. This is equal to the sprintf() and
+ * snprintf() functions.
+ */
+int trio_sprintf(char *buffer, const char *format, ...);
+int trio_vsprintf(char *buffer, const char *format, va_list args);
+int trio_sprintfv(char *buffer, const char *format, void **args);
+
+int trio_snprintf(char *buffer, size_t max, const char *format, ...);
+int trio_vsnprintf(char *buffer, size_t bufferSize, const char *format,
+ va_list args);
+int trio_snprintfv(char *buffer, size_t bufferSize, const char *format,
+ void **args);
+
+int trio_snprintfcat(char *buffer, size_t max, const char *format, ...);
+int trio_vsnprintfcat(char *buffer, size_t bufferSize, const char *format,
+ va_list args);
+
+char *trio_aprintf(const char *format, ...);
+char *trio_vaprintf(const char *format, va_list args);
+
+int trio_asprintf(char **ret, const char *format, ...);
+int trio_vasprintf(char **ret, const char *format, va_list args);
+
+/*************************************************************************
+ * Scan Functions
+ */
+int trio_scanf(const char *format, ...);
+int trio_vscanf(const char *format, va_list args);
+int trio_scanfv(const char *format, void **args);
+
+int trio_fscanf(FILE *file, const char *format, ...);
+int trio_vfscanf(FILE *file, const char *format, va_list args);
+int trio_fscanfv(FILE *file, const char *format, void **args);
+
+int trio_dscanf(int fd, const char *format, ...);
+int trio_vdscanf(int fd, const char *format, va_list args);
+int trio_dscanfv(int fd, const char *format, void **args);
+
+int trio_sscanf(const char *buffer, const char *format, ...);
+int trio_vsscanf(const char *buffer, const char *format, va_list args);
+int trio_sscanfv(const char *buffer, const char *format, void **args);
+
+/*************************************************************************
+ * Renaming
+ */
+#ifdef TRIO_REPLACE_STDIO
+/* Replace the <stdio.h> functions */
+#ifndef HAVE_PRINTF
+# define printf trio_printf
+#endif
+#ifndef HAVE_VPRINTF
+# define vprintf trio_vprintf
+#endif
+#ifndef HAVE_FPRINTF
+# define fprintf trio_fprintf
+#endif
+#ifndef HAVE_VFPRINTF
+# define vfprintf trio_vfprintf
+#endif
+#ifndef HAVE_SPRINTF
+# define sprintf trio_sprintf
+#endif
+#ifndef HAVE_VSPRINTF
+# define vsprintf trio_vsprintf
+#endif
+#ifndef HAVE_SNPRINTF
+# define snprintf trio_snprintf
+#endif
+#ifndef HAVE_VSNPRINTF
+# define vsnprintf trio_vsnprintf
+#endif
+#ifndef HAVE_SCANF
+# define scanf trio_scanf
+#endif
+#ifndef HAVE_VSCANF
+# define vscanf trio_vscanf
+#endif
+#ifndef HAVE_FSCANF
+# define fscanf trio_fscanf
+#endif
+#ifndef HAVE_VFSCANF
+# define vfscanf trio_vfscanf
+#endif
+#ifndef HAVE_SSCANF
+# define sscanf trio_sscanf
+#endif
+#ifndef HAVE_VSSCANF
+# define vsscanf trio_vsscanf
+#endif
+/* These aren't stdio functions, but we make them look similar */
+#define dprintf trio_dprintf
+#define vdprintf trio_vdprintf
+#define aprintf trio_aprintf
+#define vaprintf trio_vaprintf
+#define asprintf trio_asprintf
+#define vasprintf trio_vasprintf
+#define dscanf trio_dscanf
+#define vdscanf trio_vdscanf
+#endif
+
+/* strio compatible names */
+#define StrScan trio_sscanf
+#define StrFormat trio_sprintf
+#define StrFormatMax trio_snprintf
+#define StrFormatAlloc trio_aprintf
+#define StrFormatAppendMax trio_snprintfcat
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif
+
+#endif /* TRIO_TRIO_H */
--- /dev/null
+#ifndef __EDG_WORKLOAD_LOGGING_COMMON_ULM_PARSE_H__
+#define __EDG_WORKLOAD_LOGGING_COMMON_ULM_PARSE_H__
+
+#ident "$Header$"
+
+#include <sys/time.h> /* for ULCconvertDate */
+#include <time.h>
+
+/*========= DATA =====================================================*/
+
+#define ULM_DATE_STRING_LENGTH 21
+#define ULM_FIELDS_MAX 100 /* max number of fields */
+#define ULM_PARSE_OK 0
+#define ULM_PARSE_ERROR -1
+
+#define ULM_EQ '='
+#define ULM_QM '"'
+#define ULM_BS '\\'
+#define ULM_SP ' '
+#define ULM_TB '\t'
+#define ULM_LF '\n'
+
+typedef char *LogLine;
+
+typedef struct _edg_wll_ULMFields {
+ LogLine raw;
+ int *names;
+ int *vals;
+ int num;
+} edg_wll_ULMFields , *p_edg_wll_ULMFields;
+
+/*========= FUNCTIONS ================================================*/
+
+#define EDG_WLL_ULM_CLEAR_FIELDS(x) { if (x) { if (x->vals) free(x->vals); if (x->names) free(x->names); x->num=0; } }
+
+extern p_edg_wll_ULMFields edg_wll_ULMNewParseTable( LogLine );
+extern void edg_wll_ULMFreeParseTable(p_edg_wll_ULMFields );
+
+extern int edg_wll_ULMProcessParseTable( p_edg_wll_ULMFields );
+extern char * edg_wll_ULMGetNameAt( p_edg_wll_ULMFields, int );
+extern char * edg_wll_ULMGetValueAt ( p_edg_wll_ULMFields, int );
+
+extern double edg_wll_ULMDateToDouble( const char *s );
+void edg_wll_ULMDateToTimeval( const char *s, struct timeval *tv );
+extern int edg_wll_ULMTimevalToDate( long sec, long usec, char *dstr );
+
+#endif /* __EDG_WORKLOAD_LOGGING_COMMON_ULM_PARSE_H__ */
--- /dev/null
+#ifndef __EDG_WORKLOAD_LOGGING_COMMON_XML_CONVERSIONS_H__
+#define __EDG_WORKLOAD_LOGGING_COMMON_XML_CONVERSIONS_H__
+
+#ident "$Header$"
+
+#include "glite/lb/events.h"
+#include "glite/lb/consumer.h"
+#include "glite/lb/purge.h"
+#include "glite/lb/dump.h"
+#include "glite/lb/load.h"
+#include "glite/lb/notification.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define EDG_WLL_STAT_NO_JOBS 1024 /* private flags for edg_wll_QueryJobs */
+#define EDG_WLL_STAT_NO_STATES 2048
+
+enum edg_wll_QueryType {
+ EDG_WLL_QUERY_TYPE_UNDEF,
+ EDG_WLL_QUERY_TYPE_JOB_CONDITION,
+ EDG_WLL_QUERY_TYPE_EVENT_CONDITION,
+};
+
+typedef struct _edg_wll_XML_ctx {
+ edg_wll_Context ctx;
+ XML_Parser p;
+ char *message_body; /* copy of pointer to data to be parsed */
+ edg_wll_EventCode eventCode; /* code of processed event */
+ int position; /* row index in the result list */
+ /* always should mean 'where to write' */
+ int position2; /* used only for event_conditions */
+ int max_index; /* used in IntList */
+ int row; /* row index in QueryRec job_conditions */
+ int row2; /* row index in QueryRec event_conditions */
+ int level; /* level of XML tags nesting */
+ char element[50]; /* name of actual XML tag */
+ char *char_buf; /* for storing 'between tags' data */
+ int char_buf_len;
+ char *XML_tag; /* for handling *ListOut's tag comparisons */
+ char *XML_tag2;
+ edg_wll_QueryRec **job_conditions; /* temporal results */
+ edg_wll_QueryRec **event_conditions;
+ enum edg_wll_QueryType type;
+ int flags;
+ edg_wlc_JobId *jobsOutGlobal;
+ edg_wll_Event *eventsOutGlobal;
+ edg_wll_JobStat *jobStatGlobal;
+ edg_wll_JobStat jobStatSingleGlobal;
+ char **strListGlobal;
+ int *intListGlobal;
+ int (*tagToIndex)();
+ char *(*indexToTag)();
+ edg_wll_TagValue *tagListGlobal;
+ edg_wll_JobStat *stsListGlobal;
+ edg_wll_PurgeRequest purgeRequestGlobal;
+ edg_wll_PurgeResult purgeResultGlobal;
+ edg_wll_DumpRequest dumpRequestGlobal;
+ edg_wll_DumpResult dumpResultGlobal;
+ edg_wll_LoadRequest loadRequestGlobal;
+ edg_wll_LoadResult loadResultGlobal;
+ edg_wll_QueryRec **attrsGlobal;
+ char *notifFunction;
+ char *notifClientAddress;
+ edg_wll_NotifId notifId;
+ edg_wll_NotifChangeOp notifChangeOp;
+ time_t notifValidity;
+ int errCode;
+ int bound; /* marks 2nd value of within operator */
+ char *errDesc;
+ long stat_begin; /* begin of jobStat tag */
+ long jobQueryRec_begin; /* begin of orJobConditions tag */
+ char *errtxt; /* variable for cummulating error messages */
+ char *warntxt; /* variable for cummulating warning messages */
+} edg_wll_XML_ctx;
+
+void edg_wll_initXMLCtx(edg_wll_XML_ctx *c);
+void edg_wll_freeXMLCtx(edg_wll_XML_ctx *c);
+void edg_wll_freeBuf(edg_wll_XML_ctx *c);
+
+
+#define edg_wll_add_bool_to_XMLBody edg_wll_add_int_to_XMLBody
+#define edg_wll_add_port_to_XMLBody edg_wll_add_uint16_t_to_XMLBody
+#define edg_wll_from_string_to_bool edg_wll_from_string_to_uint16_t
+#define edg_wll_from_string_to_port edg_wll_from_string_to_int
+
+void edg_wll_add_string_to_XMLBody(char **body, const char *toAdd, const char *tag, const char *null);
+void edg_wll_add_tagged_string_to_XMLBody(char **body, const char *toAdd, const char *tag, const char *name, const char *tag2, const char *null);
+void edg_wll_add_int_to_XMLBody(char **body, const int toAdd, const char *tag, const int null);
+void edg_wll_add_timeval_to_XMLBody(char **body, struct timeval toAdd, const char *tag, const struct timeval null);
+void edg_wll_add_jobid_to_XMLBody(char **body, edg_wlc_JobId toAdd, const char *tag, const void *null);
+void edg_wll_add_notifid_to_XMLBody(char **body, edg_wll_NotifId toAdd, const char *tag, const void *null);
+void edg_wll_add_edg_wll_JobStatCode_to_XMLBody(char **body, edg_wll_JobStatCode toAdd, const char *tag, const edg_wll_JobStatCode null);
+void edg_wll_add_edg_wll_EventCode_to_XMLBody(char **body, edg_wll_EventCode toAdd, const char *tag, const edg_wll_EventCode null);
+void edg_wll_add_time_t_to_XMLBody(char **body, const time_t toAdd, const char *tag, const time_t null);
+void edg_wll_add_tagged_time_t_to_XMLBody(char **body, const time_t toAdd, const char *tag, const char *name, const char *tag2, const time_t null);
+void edg_wll_add_uint16_t_to_XMLBody(char **body, const uint16_t toAdd, const char *tag, const uint16_t null);
+void edg_wll_add_logsrc_to_XMLBody(char **body, const edg_wll_Source toAdd, const char *tag, const edg_wll_Source null);
+void edg_wll_add_intlist_to_XMLBody(char **body, const int *toAdd, const char *tag, char *(*indexToTag)(), const char *indent, const int from, const int to);
+void edg_wll_add_strlist_to_XMLBody(char **body, char * const *toAdd, const char *tag, const char *subTag, const char *indent, const char *null);
+void edg_wll_add_taglist_to_XMLBody(char **body, const edg_wll_TagValue *toAdd, const char *tag, const char *subTag, const char *indent, const char *subTag2, const char *null);
+void edg_wll_add_time_t_list_to_XMLBody(char **body, const time_t *toAdd, const char *tag, char *(*indexToTag)(), const char *indent, const int from, const int to);
+char *edg_wll_from_string_to_string(edg_wll_XML_ctx *XMLCtx);
+edg_wlc_JobId edg_wll_from_string_to_jobid(edg_wll_XML_ctx *XMLCtx);
+edg_wll_NotifId edg_wll_from_string_to_notifid(edg_wll_XML_ctx *XMLCtx);
+edg_wll_JobStatCode edg_wll_from_string_to_edg_wll_JobStatCode(edg_wll_XML_ctx *XMLCtx);
+int edg_wll_from_string_to_int(edg_wll_XML_ctx *XMLCtx);
+long edg_wll_from_string_to_long(edg_wll_XML_ctx *XMLCtx);
+uint16_t edg_wll_from_string_to_uint16_t(edg_wll_XML_ctx *XMLCtx);
+struct timeval edg_wll_from_string_to_timeval(edg_wll_XML_ctx *XMLCtx);
+time_t edg_wll_from_string_to_time_t(edg_wll_XML_ctx *XMLCtx);
+edg_wll_Source edg_wll_from_string_to_logsrc(edg_wll_XML_ctx *XMLCtx);
+
+char *edg_wll_stat_flags_to_string(int flags);
+int edg_wll_string_to_stat_flags(char *cflags);
+char *edg_wll_purge_flags_to_string(int flags);
+int edg_wll_string_to_purge_flags(char *cflags);
+int edg_wll_StringToDumpConst(const char *name);
+char *edg_wll_DumpConstToString(int dumpConst);
+int edg_wll_StringTodone_code(const char *name);
+char *edg_wll_done_codeToString(int done_codeConst);
+edg_wll_QueryAttr edg_wll_StringToquery_attr(const char *name);
+char *edg_wll_query_attrToString(edg_wll_QueryAttr query_attrConst);
+edg_wll_NotifChangeOp edg_wll_StringToNotifChangeOp(const char *name);
+char *edg_wll_NotifChangeOpToString(edg_wll_NotifChangeOp notifChangeOpConst);
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
+
+#endif /* __EDG_WORKLOAD_LOGGING_COMMON_XML_CONVERSIONS_H__ */
--- /dev/null
+#ifndef __EDG_WORKLOAD_LOGGING_COMMON_XML_PARSE_H__
+#define __EDG_WORKLOAD_LOGGING_COMMON_XML_PARSE_H__
+
+#ident "$Header$"
+
+
+#include "glite/lb/purge.h"
+#include "glite/lb/dump.h"
+#include "glite/lb/load.h"
+#include "glite/lb/producer.h"
+#include "glite/lb/notification.h"
+
+/* function for parsing XML responses from server */
+
+extern edg_wll_ErrorCode edg_wll_ParseQueryEvents(edg_wll_Context, char *, edg_wll_Event **);
+
+extern edg_wll_ErrorCode edg_wll_ParseQueryJobs(edg_wll_Context, char *, edg_wlc_JobId **, edg_wll_JobStat **);
+
+extern edg_wll_ErrorCode edg_wll_ParseUserJobs(edg_wll_Context, char *, edg_wlc_JobId **);
+
+extern edg_wll_ErrorCode edg_wll_ParseJobStat(edg_wll_Context ctx, char *messageBody, long len, edg_wll_JobStat *stat);
+
+extern edg_wll_ErrorCode edg_wll_ParseStrList(edg_wll_Context ctx, char *messageBody, long len, char *tag, char *tag2, char ***strListOut);
+
+extern edg_wll_ErrorCode edg_wll_ParseIntList(edg_wll_Context ctx, char *messageBody, long len, char *tag, int (*tagToIndex)(), int **intListOut);
+
+extern edg_wll_ErrorCode edg_wll_ParseTagList(edg_wll_Context ctx, char *messageBody, long len, char *tag, char *tag2, edg_wll_TagValue **tagListOut);
+
+extern edg_wll_ErrorCode edg_wll_ParseStsList(edg_wll_Context ctx, char *messageBody, long len, char *tag, char *tag2, edg_wll_JobStat **stsListOut);
+
+extern edg_wll_ErrorCode edg_wll_ParsePurgeResult(edg_wll_Context ctx, char *messageBody, edg_wll_PurgeResult *result);
+
+extern edg_wll_ErrorCode edg_wll_ParseDumpResult(edg_wll_Context ctx, char *messageBody, edg_wll_DumpResult *result);
+
+extern edg_wll_ErrorCode edg_wll_ParseLoadResult(edg_wll_Context ctx, char *messageBody, edg_wll_LoadResult *result);
+
+extern edg_wll_ErrorCode edg_wll_ParseIndexedAttrs(edg_wll_Context ctx, char *messageBody, edg_wll_QueryRec ***attrs);
+
+extern edg_wll_ErrorCode edg_wll_ParseNotifResult(edg_wll_Context ctx, char *messageBody, time_t *validity);
+
+extern int edg_wll_QueryEventsRequestToXML(edg_wll_Context ctx, const edg_wll_QueryRec **job_conditions, const edg_wll_QueryRec **event_conditions, char **send_mess);
+
+extern int edg_wll_JobQueryRecToXML(edg_wll_Context ctx, edg_wll_QueryRec const * const *conditions, char **send_mess);
+
+extern int edg_wll_QueryJobsRequestToXML(edg_wll_Context ctx, const edg_wll_QueryRec **conditions, int flags, char **send_mess);
+
+extern int edg_wll_PurgeRequestToXML(edg_wll_Context ctx, const edg_wll_PurgeRequest *request, char **message);
+
+extern int edg_wll_DumpRequestToXML(edg_wll_Context ctx, const edg_wll_DumpRequest *request, char **message);
+
+extern int edg_wll_LoadRequestToXML(edg_wll_Context ctx, const edg_wll_LoadRequest *request, char **message);
+
+extern int edg_wll_IndexedAttrsRequestToXML(edg_wll_Context ctx, char **message);
+
+extern int edg_wll_NotifRequestToXML( edg_wll_Context ctx, const char *function, const edg_wll_NotifId notifId, const char *address, edg_wll_NotifChangeOp op, edg_wll_QueryRec const * const *conditions, char **message);
+
+
+#endif /* __EDG_WORKLOAD_LOGGING_COMMON_XML_PARSE_H__ */
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+
+<project name="LB Common component common properties">
+
+ <property file="build.properties" />
+ <property name="subsystem.name" value="${lb.subsystem.name}"/>
+ <property name="subsystem.prefix" value="${lb.subsystem.prefix}"/>
+ <property name="component.prefix" value="common" />
+
+ <import file="${component.general.properties.file}" />
+
+</project>
--- /dev/null
+#ident "$Header$"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <assert.h>
+
+#include <globus_config.h>
+#include "glite/wms/thirdparty/globus_ssl_utils/sslutils.h"
+
+#include "glite/wms/jobid/strmd5.h"
+#include "glite/wms/jobid/cjobid.h"
+#include "context-int.h"
+#include "glite/lb/producer.h"
+
+static void free_voms_groups(edg_wll_VomsGroups *);
+
+int edg_wll_InitContext(edg_wll_Context *ctx)
+{
+ int i;
+ edg_wll_Context out = (edg_wll_Context) malloc(sizeof(*out));
+
+ if (!out) return ENOMEM;
+ memset(out,0,sizeof(*out));
+ assert(out->errDesc == NULL);
+
+ out->allowAnonymous = 1;
+ out->notifSock = -1;
+
+ /* XXX */
+ for (i=0; i<EDG_WLL_PARAM__LAST; i++) edg_wll_SetParam(out,i,NULL);
+
+ out->connPool = (edg_wll_ConnPool *) calloc(out->poolSize, sizeof(edg_wll_ConnPool));
+
+ *ctx = out;
+ return 0;
+}
+
+void edg_wll_FreeContext(edg_wll_Context ctx)
+{
+ struct timeval close_timeout = {0, 50000};
+
+ if (!ctx) return;
+
+ if (ctx->errDesc) free(ctx->errDesc);
+ if (ctx->connPool) {
+ int i;
+
+ for (i=0; i<ctx->poolSize; i++) {
+ if (ctx->connPool[i].peerName) free(ctx->connPool[i].peerName);
+ if (ctx->connPool[i].ssl)
+ edg_wll_ssl_close_timeout(ctx->connPool[i].ssl,&close_timeout);
+ if (ctx->connPool[i].gsiCred) edg_wll_ssl_free(ctx->connPool[i].gsiCred);
+ if (ctx->connPool[i].buf) free(ctx->connPool[i].buf);
+ }
+ free(ctx->connPool);
+ }
+ if (ctx->notifSock >=0) close(ctx->notifSock);
+ if (ctx->srvName) free(ctx->srvName);
+ if (ctx->peerName) free(ctx->peerName);
+ if (ctx->vomsGroups.len) free_voms_groups(&ctx->vomsGroups);
+ if (ctx->dumpStorage) free(ctx->dumpStorage);
+ if (ctx->purgeStorage) free(ctx->purgeStorage);
+
+ if (ctx->p_jobid) edg_wlc_JobIdFree(ctx->p_jobid);
+ if (ctx->p_host) free(ctx->p_host);
+ if (ctx->p_instance) free(ctx->p_instance);
+ if (ctx->p_destination) free(ctx->p_destination);
+ if (ctx->p_query_server) free(ctx->p_query_server);
+ if (ctx->p_notif_server) free(ctx->p_notif_server);
+ if (ctx->p_proxy_filename) free(ctx->p_proxy_filename);
+ if (ctx->p_cert_filename) free(ctx->p_cert_filename);
+ if (ctx->p_key_filename) free(ctx->p_key_filename);
+
+ /* do not free (references only)
+ * ctx->job_index
+ * ctx->job_index_cols
+ * ctx->mysql */
+
+ free(ctx);
+}
+
+static const char* const errTexts[] = {
+ /* standard error strings should appear here */
+ "Broken ULM",
+ "Undefined event",
+ "Message incomplete",
+ "Duplicate ULM key",
+ "Misuse of ULM key",
+ "Warning: extra ULM fields",
+ "XML Parse error",
+ "Server response error",
+ "Bad JobId format",
+ "Database call failed",
+ "Bad URL format",
+ "MD5 key clash",
+ "SSL Error",
+ "DNS resolver error",
+ "No JobId specified in context",
+ "No indexed condition in query",
+ "Interlogger protocol error",
+ "Interlogger internal error",
+ "Interlogger has events pending"
+};
+
+const char *edg_wll_GetErrorText(int code) {
+ return code ?
+ (code <= EDG_WLL_ERROR_BASE ?
+ strerror(code) :
+ errTexts[code - EDG_WLL_ERROR_BASE - 1]
+ ) :
+ NULL;
+}
+
+int edg_wll_Error(edg_wll_Context ctx, char **errText, char **errDesc)
+{
+ char *text = NULL,*desc = NULL;
+ const char* et = edg_wll_GetErrorText(ctx->errCode);
+
+ if (et) {
+ text = strdup(et);
+ if (ctx->errDesc) desc = (char *) strdup(ctx->errDesc);
+ }
+
+ if (errText) *errText = text; else free(text);
+ if (errDesc) *errDesc = desc; else free(desc);
+ return ctx->errCode;
+}
+
+int edg_wll_ResetError(edg_wll_Context ctx)
+{
+ if (ctx->errDesc) free(ctx->errDesc);
+ ctx->errDesc = NULL;
+ ctx->errCode = 0;
+
+ return ctx->errCode;
+}
+
+int edg_wll_SetError(edg_wll_Context ctx,int code,const char *desc)
+{
+ edg_wll_ResetError(ctx);
+ if (code) {
+ ctx->errCode = code;
+ if (desc) ctx->errDesc = (char *) strdup(desc);
+ }
+
+ return ctx->errCode;
+}
+
+
+int edg_wll_UpdateError(edg_wll_Context ctx,int code,const char *desc)
+{
+ char *new_desc=NULL;
+ char *old_desc=NULL;
+ const char* err_text = edg_wll_GetErrorText(ctx->errCode);
+
+ /* first fill in the old_desc */
+ if (ctx->errCode) {
+ if (ctx->errDesc) {
+ if ((err_text)) // && (code) && (code <> ctx->errCode))
+ asprintf(&old_desc,"%s;; %s",err_text,ctx->errDesc);
+ else
+ old_desc = (char *) strdup(ctx->errDesc);
+ } else {
+ old_desc = (char *) strdup(err_text);
+ }
+ } else {
+ if (ctx->errDesc) old_desc = (char *) strdup(ctx->errDesc);
+ }
+ if (ctx->errDesc) free(ctx->errDesc);
+
+ /* update errDesc */
+ if (old_desc) {
+ if (desc) {
+ asprintf(&new_desc,"%s;; %s",desc,old_desc);
+ ctx->errDesc = (char *) strdup(new_desc);
+ } else {
+ ctx->errDesc = (char *) strdup(old_desc);
+ }
+ } else {
+ if (desc) ctx->errDesc = (char *) strdup(desc);
+ }
+
+ /* update errCode */
+ if (code) {
+ ctx->errCode = code;
+ }
+
+ if (new_desc) free(new_desc);
+ if (old_desc) free(old_desc);
+
+ return ctx->errCode;
+}
+
+static const char* const srcNames[] = {
+ "Undefined",
+ "UserInterface",
+ "NetworkServer",
+ "WorkloadManager",
+ "BigHelper",
+ "JobController",
+ "LogMonitor",
+ "LRMS",
+ "Application",
+};
+
+edg_wll_Source edg_wll_StringToSource(const char *name)
+{
+ int i;
+/* XXX: remove
+ for (i=1; srcNames[i] && strcmp(name,srcNames[i]); i++);
+ return srcNames[i] ? i : EDG_WLL_SOURCE_NONE;
+*/
+ for (i=1; i<sizeof(srcNames)/sizeof(srcNames[0]); i++)
+ if (strcasecmp(srcNames[i],name) == 0) return (edg_wll_Source) i;
+ return EDG_WLL_SOURCE_NONE;
+}
+
+char * edg_wll_SourceToString(edg_wll_Source src)
+{
+ if (src < EDG_WLL_SOURCE_NONE || src >= EDG_WLL_SOURCE__LAST) return NULL;
+ return strdup(srcNames[src]);
+}
+
+static const char* const queryResultNames[] = {
+ "Undefined",
+ "None",
+ "All",
+ "Limited"
+};
+
+edg_wll_QueryResults edg_wll_StringToQResult(const char *name)
+{
+ int i;
+
+ for (i=1; i<sizeof(queryResultNames)/sizeof(queryResultNames[0]); i++)
+ if (strcasecmp(queryResultNames[i],name) == 0)
+ return (edg_wll_QueryResults) i;
+
+ return EDG_WLL_QUERYRES_UNDEF;
+}
+
+char * edg_wll_QResultToString(edg_wll_QueryResults res)
+{
+ if (res < EDG_WLL_QUERYRES_NONE || res >= EDG_WLL_QUERYRES__LAST)
+ return NULL;
+
+ return strdup(queryResultNames[res]);
+}
+
+
+char *edg_wll_GetSequenceCode(const edg_wll_Context ctx)
+{
+ unsigned int *c;
+ char *ret = NULL;
+
+ c = &ctx->p_seqcode.c[0];
+ asprintf(&ret, "UI=%06d:NS=%010d:WM=%06d:BH=%010d:JSS=%06d"
+ ":LM=%06d:LRMS=%06d:APP=%06d",
+ c[EDG_WLL_SOURCE_USER_INTERFACE],
+ c[EDG_WLL_SOURCE_NETWORK_SERVER],
+ c[EDG_WLL_SOURCE_WORKLOAD_MANAGER],
+ c[EDG_WLL_SOURCE_BIG_HELPER],
+ c[EDG_WLL_SOURCE_JOB_SUBMISSION],
+ c[EDG_WLL_SOURCE_LOG_MONITOR],
+ c[EDG_WLL_SOURCE_LRMS],
+ c[EDG_WLL_SOURCE_APPLICATION]);
+ return ret;
+}
+
+int edg_wll_SetSequenceCode(edg_wll_Context ctx,
+ const char * seqcode_str, int seq_type)
+{
+ int res;
+ unsigned int *c;
+ int duplicate = 0;
+
+ edg_wll_ResetError(ctx);
+
+ if (seq_type == EDG_WLL_SEQ_DUPLICATE) {
+ duplicate = 1;
+ } else if (seq_type != EDG_WLL_SEQ_NORMAL)
+ return edg_wll_SetError(ctx, EINVAL,
+ "edg_wll_SetSequenceCode(): unrecognized value of seq_type parameter");
+
+ if (!seqcode_str) {
+ memset(&ctx->p_seqcode,0,sizeof ctx->p_seqcode);
+ return 0;
+ }
+
+ c = &ctx->p_seqcode.c[0];
+ res = sscanf(seqcode_str, "UI=%d:NS=%d:WM=%d:BH=%d:JSS=%d:LM=%d:LRMS=%d:APP=%d",
+ &c[EDG_WLL_SOURCE_USER_INTERFACE],
+ &c[EDG_WLL_SOURCE_NETWORK_SERVER],
+ &c[EDG_WLL_SOURCE_WORKLOAD_MANAGER],
+ &c[EDG_WLL_SOURCE_BIG_HELPER],
+ &c[EDG_WLL_SOURCE_JOB_SUBMISSION],
+ &c[EDG_WLL_SOURCE_LOG_MONITOR],
+ &c[EDG_WLL_SOURCE_LRMS],
+ &c[EDG_WLL_SOURCE_APPLICATION]);
+
+ assert(EDG_WLL_SOURCE__LAST == 9);
+ if (res != EDG_WLL_SOURCE__LAST-1)
+ return edg_wll_SetError(ctx, EINVAL, "edg_wll_SetSequenceCode(): syntax error in sequence code");
+
+ if (duplicate) {
+ if (ctx->p_source <= EDG_WLL_SOURCE_NONE || ctx->p_source >= EDG_WLL_SOURCE__LAST)
+ return edg_wll_SetError(ctx,EINVAL,"edg_wll_SetSequenceCode(): context param: source missing");
+ c[ctx->p_source] = time(NULL);
+ }
+
+ return edg_wll_Error(ctx, NULL, NULL);
+}
+
+int edg_wll_IncSequenceCode(edg_wll_Context ctx)
+{
+ edg_wll_ResetError(ctx);
+
+ if (ctx->p_source <= EDG_WLL_SOURCE_NONE || ctx->p_source >= EDG_WLL_SOURCE__LAST)
+ return edg_wll_SetError(ctx,EINVAL,"edg_wll_IncSequenceCode(): context param: source missing");
+
+ ctx->p_seqcode.c[ctx->p_source]++;
+
+ return edg_wll_Error(ctx, NULL, NULL);
+}
+
+int edg_wll_GetLoggingJob(const edg_wll_Context ctx,edg_wlc_JobId *out)
+{
+ return edg_wlc_JobIdDup(ctx->p_jobid,out);
+}
+
+int edg_wll_GenerateSubjobIds(
+ edg_wll_Context ctx,
+ const edg_wlc_JobId parent,
+ int num_subjobs,
+ const char * seed,
+ edg_wlc_JobId ** subjobs)
+{
+ int subjob, ret;
+ char *p_unique, *p_bkserver, *intseed;
+ char *unhashed, *hashed;
+ unsigned int p_port;
+ edg_wlc_JobId *retjobs;
+
+
+ if (num_subjobs < 1)
+ return edg_wll_SetError(ctx, EINVAL,
+ "edg_wll_GenerateSubjobIds(): num_subjobs < 1");
+ if (seed == NULL)
+ intseed = edg_wll_GetSequenceCode(ctx);
+ else
+ intseed = strdup(seed);
+
+ p_unique = edg_wlc_JobIdGetUnique(parent);
+ edg_wlc_JobIdGetServerParts(parent, &p_bkserver, &p_port);
+
+ retjobs = calloc(num_subjobs+1, sizeof(edg_wlc_JobId));
+
+ if (p_unique == NULL ||
+ intseed == NULL ||
+ p_bkserver == NULL ||
+ retjobs == NULL)
+ return edg_wll_SetError(ctx, ENOMEM, NULL);
+
+ for (subjob = 0; subjob < num_subjobs; subjob++) {
+
+ asprintf(&unhashed, "%s,%s,%d", p_unique, intseed, subjob);
+ if (unhashed == NULL) {
+ edg_wll_SetError(ctx, ENOMEM, "edg_wll_GenerateSubjobIds(): asprintf() error");
+ goto handle_error;
+ }
+
+ hashed = str2md5base64(unhashed);
+ free(unhashed);
+ if (hashed == NULL) {
+ edg_wll_SetError(ctx, ENOMEM, "edg_wll_GenerateSubjobIds(): str2md5base64() error");
+ goto handle_error;
+ }
+
+ ret = edg_wlc_JobIdRecreate(p_bkserver, p_port, hashed, &retjobs[subjob]);
+ free(hashed);
+ if (ret != 0) {
+ edg_wll_SetError(ctx, ret, "edg_wll_GenerateSubjobIds(): edg_wlc_JobIdRecreate() error");
+ goto handle_error;
+ }
+ }
+
+ free(intseed);
+ free(p_unique);
+ free(p_bkserver);
+
+ *subjobs = retjobs;
+ return 0;
+
+ handle_error:
+ free(intseed);
+ free(p_unique);
+ free(p_bkserver);
+ for ( subjob-- ;subjob >= 0; subjob--)
+ edg_wlc_JobIdFree(retjobs[subjob]);
+ return edg_wll_Error(ctx, NULL, NULL);
+}
+
+static void
+free_voms_groups(edg_wll_VomsGroups *groups)
+{
+ size_t len;
+
+ if (groups == NULL)
+ return;
+
+ for (len = 0; len < groups->len; len++) {
+ if (groups->val[len].vo)
+ free(groups->val[len].vo);
+ if (groups->val[len].name)
+ free(groups->val[len].name);
+ }
+}
--- /dev/null
+#ident "$Header$"
+
+#include <string.h>
+#include <stdio.h>
+#include <fcntl.h>
+#include <time.h>
+#include <stdlib.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include <sys/socket.h>
+#include <netdb.h>
+#include <netinet/in.h>
+#include <ares.h>
+
+#include "globus_config.h"
+#include "glite/wms/thirdparty/globus_ssl_utils/sslutils.h"
+
+#include "dgssl.h"
+
+/* This two functions are not in globus sslutils.h */
+void proxy_verify_ctx_release(proxy_verify_ctx_desc *pvxd);
+void proxy_verify_ctx_init(proxy_verify_ctx_desc *pvxd);
+
+#include "globus_gss_assist.h"
+
+#define tv_sub(a,b) {\
+ (a).tv_usec -= (b).tv_usec;\
+ (a).tv_sec -= (b).tv_sec;\
+ if ((a).tv_usec < 0) {\
+ (a).tv_sec--;\
+ (a).tv_usec += 1000000;\
+ }\
+}
+
+static int decrement_timeout(struct timeval *timeout, struct timeval before, struct timeval after)
+{
+ (*timeout).tv_sec = (*timeout).tv_sec - (after.tv_sec - before.tv_sec);
+ (*timeout).tv_usec = (*timeout).tv_usec - (after.tv_usec - before.tv_usec);
+ while ( (*timeout).tv_usec < 0) {
+ (*timeout).tv_sec--;
+ (*timeout).tv_usec += 1000000;
+ }
+ if ( ((*timeout).tv_sec < 0) || (((*timeout).tv_sec == 0) && ((*timeout).tv_usec == 0)) ) return(1);
+ else return(0);
+}
+
+
+static int handle_ssl_error(int sock,int err,struct timeval *to);
+
+static unsigned char dh512_p[]={
+ 0xDA,0x58,0x3C,0x16,0xD9,0x85,0x22,0x89,0xD0,0xE4,0xAF,0x75,
+ 0x6F,0x4C,0xCA,0x92,0xDD,0x4B,0xE5,0x33,0xB8,0x04,0xFB,0x0F,
+ 0xED,0x94,0xEF,0x9C,0x8A,0x44,0x03,0xED,0x57,0x46,0x50,0xD3,
+ 0x69,0x99,0xDB,0x29,0xD7,0x76,0x27,0x6B,0xA2,0xD3,0xD4,0x12,
+ 0xE2,0x18,0xF4,0xDD,0x1E,0x08,0x4C,0xF6,0xD8,0x00,0x3E,0x7C,
+ 0x47,0x74,0xE8,0x33,
+ };
+static unsigned char dh512_g[]={
+ 0x02,
+ };
+
+static DH *get_dh512(void)
+ {
+ DH *dh=NULL;
+
+ if ((dh=DH_new()) == NULL) return(NULL);
+ dh->p=BN_bin2bn(dh512_p,sizeof(dh512_p),NULL);
+ dh->g=BN_bin2bn(dh512_g,sizeof(dh512_g),NULL);
+ if ((dh->p == NULL) || (dh->g == NULL))
+ return(NULL);
+ return(dh);
+ }
+
+struct asyn_result {
+ struct hostent *ent;
+ int err;
+};
+
+/* ares callback handler for ares_gethostbyname() */
+static void callback_handler(void *arg, int status, struct hostent *h) {
+ struct asyn_result *arp = (struct asyn_result *) arg;
+
+ switch (status) {
+ case ARES_SUCCESS:
+ if (h && h->h_addr_list[0]) {
+ arp->ent->h_addr_list =
+ (char **) malloc(2 * sizeof(char *));
+ if (arp->ent->h_addr_list == NULL) {
+ arp->err = NETDB_INTERNAL;
+ break;
+ }
+ arp->ent->h_addr_list[0] =
+ malloc(sizeof(struct in_addr));
+ if (arp->ent->h_addr_list[0] == NULL) {
+ free(arp->ent->h_addr_list);
+ arp->err = NETDB_INTERNAL;
+ break;
+ }
+ memcpy(arp->ent->h_addr_list[0], h->h_addr_list[0],
+ sizeof(struct in_addr));
+ arp->ent->h_addr_list[1] = NULL;
+ arp->err = NETDB_SUCCESS;
+ } else {
+ arp->err = NO_DATA;
+ }
+ break;
+ case ARES_EBADNAME:
+ case ARES_ENOTFOUND:
+ arp->err = HOST_NOT_FOUND;
+ break;
+ case ARES_ENOTIMP:
+ arp->err = NO_RECOVERY;
+ break;
+ case ARES_ENOMEM:
+ case ARES_EDESTRUCTION:
+ default:
+ arp->err = NETDB_INTERNAL;
+ break;
+ }
+}
+
+
+static void free_hostent(struct hostent *h){
+ int i;
+
+ if (h) {
+ if (h->h_name) free(h->h_name);
+ if (h->h_aliases) {
+ for (i=0; h->h_aliases[i]; i++) free(h->h_aliases[i]);
+ free(h->h_aliases);
+ }
+ if (h->h_addr_list) {
+ for (i=0; h->h_addr_list[i]; i++) free(h->h_addr_list[i]);
+ free(h->h_addr_list);
+ }
+ free(h);
+ }
+}
+
+static int asyn_gethostbyname(char **addrOut, char const *name, struct timeval *timeout) {
+ struct asyn_result ar;
+ ares_channel channel;
+ int nfds;
+ fd_set readers, writers;
+ struct timeval tv, *tvp;
+ struct timeval start_time,check_time;
+
+
+/* start timer */
+ gettimeofday(&start_time,0);
+
+/* ares init */
+ if ( ares_init(&channel) != ARES_SUCCESS ) return(NETDB_INTERNAL);
+ ar.ent = (struct hostent *) calloc (sizeof(*ar.ent),1);
+
+/* query DNS server asynchronously */
+ ares_gethostbyname(channel, name, AF_INET, callback_handler,
+ (void *) &ar);
+
+/* wait for result */
+ while (1) {
+ FD_ZERO(&readers);
+ FD_ZERO(&writers);
+ nfds = ares_fds(channel, &readers, &writers);
+ if (nfds == 0)
+ break;
+
+ gettimeofday(&check_time,0);
+ if (decrement_timeout(timeout, start_time, check_time)) {
+ ares_destroy(channel);
+ free_hostent(ar.ent);
+ return(TRY_AGAIN);
+ }
+ start_time = check_time;
+
+ tvp = ares_timeout(channel, timeout, &tv);
+
+ switch ( select(nfds, &readers, &writers, NULL, tvp) ) {
+ case -1: if (errno != EINTR) {
+ ares_destroy(channel);
+ free_hostent(ar.ent);
+ return NETDB_INTERNAL;
+ } else
+ continue;
+ case 0:
+ FD_ZERO(&readers);
+ FD_ZERO(&writers);
+ /* fallthrough */
+ default: ares_process(channel, &readers, &writers);
+ }
+ }
+
+
+ ares_destroy(channel);
+
+ if (ar.err == NETDB_SUCCESS) {
+ *addrOut = malloc(sizeof(struct in_addr));
+ memcpy(*addrOut,ar.ent->h_addr_list[0], sizeof(struct in_addr));
+ free_hostent(ar.ent);
+ }
+ return(ar.err);
+}
+
+
+
+void edg_wll_ssl_set_noauth(proxy_cred_desc* cred_handle)
+{ DH *dh=NULL;
+
+ SSL_CTX_set_cipher_list(cred_handle->gs_ctx,
+ "ADH:RSA:HIGH:MEDIUM:LOW:EXP:+eNULL:+aNULL");
+ dh=get_dh512();
+ SSL_CTX_set_tmp_dh(cred_handle->gs_ctx,dh);
+ DH_free(dh);
+}
+
+proxy_cred_desc *edg_wll_ssl_init(int verify, int callback, char *p_cert_file,char *p_key_file,
+ int ask_passwd, int noauth)
+{
+ proxy_cred_desc * cred_handle = NULL;
+ char *certdir=NULL;
+ int (*pw_cb)() = NULL;
+ int load_err = 0;
+
+ if (ask_passwd == 0)
+ pw_cb = proxy_password_callback_no_prompt;
+
+ cred_handle = proxy_cred_desc_new();
+ proxy_get_filenames(cred_handle,1,NULL,&certdir,NULL,NULL,NULL);
+ if (!noauth) {
+ if ((p_cert_file!=NULL) && (p_key_file!=NULL)) {
+ load_err = proxy_load_user_cert(cred_handle,p_cert_file,NULL,NULL);
+ if (load_err == 0)
+ load_err = proxy_load_user_key(cred_handle,p_key_file,pw_cb,NULL);
+ if (load_err == 0) {
+ if (proxy_check_proxy_name(cred_handle->ucert)>0) {
+ cred_handle->type =CRED_TYPE_PROXY;
+ if (cred_handle->cert_chain == NULL)
+ cred_handle->cert_chain = sk_X509_new_null();
+ proxy_load_user_proxy(cred_handle->cert_chain,p_cert_file,NULL);
+ /*
+ if (cred_handle->cert_chain)
+ for (int i=0;i<sk_X509_num(cred_handle->cert_chain);i++)
+ X509_STORE_add_cert(cred_handle->gs_ctx->cert_store,
+ sk_X509_value(cred_handle->cert_chain,i));
+ */
+ } else cred_handle->type = CRED_TYPE_PERMANENT;
+ }
+ }
+ if (load_err == 0)
+ proxy_init_cred(cred_handle,pw_cb,NULL);
+ }
+
+ if ( (cred_handle->gs_ctx != NULL
+ && !SSL_CTX_check_private_key(cred_handle->gs_ctx))
+ || noauth == 1
+ || load_err) {
+ if (cred_handle->ucert != NULL) {
+ X509_free(cred_handle->ucert);
+ cred_handle->ucert = NULL;
+ }
+ if (cred_handle->upkey != NULL) {
+ EVP_PKEY_free(cred_handle->upkey);
+ cred_handle->upkey = NULL;
+ }
+ if (cred_handle->gs_ctx)
+ SSL_CTX_free(cred_handle->gs_ctx);
+ cred_handle->gs_ctx=SSL_CTX_new(SSLv3_method());
+ SSL_CTX_set_options(cred_handle->gs_ctx,0);
+ SSL_CTX_sess_set_cache_size(cred_handle->gs_ctx,5);
+ SSL_CTX_load_verify_locations(cred_handle->gs_ctx,NULL,certdir);
+ }
+
+ if (cred_handle->gs_ctx != NULL) {
+ SSL_CTX_set_verify(cred_handle->gs_ctx,verify,
+ (callback==0)?NULL:proxy_verify_callback);
+ SSL_CTX_set_purpose(cred_handle->gs_ctx,X509_PURPOSE_ANY);
+ SSL_CTX_set_session_id_context(cred_handle->gs_ctx, "DG_BKSERVER",
+ strlen("DG_BKSERVER"));
+ if (noauth == 1)
+ edg_wll_ssl_set_noauth(cred_handle);
+ }
+
+ free(certdir);
+ return(cred_handle);
+}
+
+void edg_wll_ssl_get_my_subject(proxy_cred_desc *cred_handle, char **my_subject_name)
+{
+ if ((my_subject_name!=NULL) && (cred_handle->ucert!=NULL))
+ *my_subject_name=X509_NAME_oneline(X509_get_subject_name(
+ cred_handle->ucert), NULL, 0);
+}
+
+void edg_wll_ssl_get_my_subject_base(proxy_cred_desc *cred_handle, char **my_subject_name)
+{
+ X509_NAME *base;
+ if ((my_subject_name!=NULL) && (cred_handle->ucert!=NULL)) {
+ X509_NAME *s = X509_get_subject_name(cred_handle->ucert);
+
+ base = X509_NAME_dup(s);
+ proxy_get_base_name(base);
+ *my_subject_name=strdup(X509_NAME_oneline(base,NULL, 0));
+ X509_NAME_free(base);
+ }
+}
+
+int edg_wll_ssl_free(proxy_cred_desc * cred_handle)
+{ return(proxy_cred_desc_free(cred_handle));
+}
+
+int edg_wll_ssl_connect(proxy_cred_desc *cred_handle,char const *hostname,int port,
+ struct timeval *timeout,SSL **sslp)
+{
+ int sock,ret;
+ struct sockaddr_in a;
+ SSL_CTX *ctx;
+ SSL *ssl;
+ struct timeval before,after,to;
+ int sock_err;
+ socklen_t err_len;
+ char *certdir=NULL, *addr;
+ proxy_verify_ctx_desc verify_ctx_area;
+ proxy_verify_desc verify_area;
+ int h_errno;
+
+
+ sock = socket(AF_INET, SOCK_STREAM, 0);
+ if (sock < 0) return EDG_WLL_SSL_ERROR_ERRNO;
+
+ if (timeout) {
+ int flags = fcntl(sock, F_GETFL, 0);
+ if (fcntl(sock, F_SETFL, flags | O_NONBLOCK) < 0)
+ return EDG_WLL_SSL_ERROR_ERRNO;
+ gettimeofday(&before,NULL);
+ }
+
+ switch (h_errno = asyn_gethostbyname(&addr, hostname, timeout)) {
+ case NETDB_SUCCESS:
+ memset(&a,0,sizeof a);
+ a.sin_family = AF_INET;
+ memcpy(&a.sin_addr.s_addr,addr,sizeof a.sin_addr.s_addr);
+ a.sin_port = htons(port);
+ free(addr);
+ break;
+ case TRY_AGAIN:
+ close(sock);
+ return EDG_WLL_SSL_ERROR_TIMEOUT;
+ case NETDB_INTERNAL:
+ /* fall through */
+ default:
+ close(sock);
+ /* h_errno may be thread safe with Linux pthread libs,
+ * but such an assumption is not portable
+ */
+ errno = h_errno;
+ return EDG_WLL_SSL_ERROR_HERRNO;
+ }
+
+ if (connect(sock,(struct sockaddr *) &a,sizeof a) < 0) {
+ if (timeout && errno == EINPROGRESS) {
+ fd_set fds;
+ FD_ZERO(&fds);
+ FD_SET(sock,&fds);
+ memcpy(&to,timeout,sizeof to);
+ gettimeofday(&before,NULL);
+ switch (select(sock+1,NULL,&fds,NULL,&to)) {
+ case -1: close(sock);
+ return EDG_WLL_SSL_ERROR_ERRNO;
+ case 0: close(sock);
+ return EDG_WLL_SSL_ERROR_TIMEOUT;
+ }
+ gettimeofday(&after,NULL);
+ tv_sub(after,before);
+ tv_sub(*timeout,after);
+
+ err_len = sizeof sock_err;
+ if (getsockopt(sock,SOL_SOCKET,SO_ERROR,&sock_err,&err_len)) {
+ close(sock);
+ return EDG_WLL_SSL_ERROR_ERRNO;
+ }
+ if (sock_err) {
+ close(sock);
+ errno = sock_err;
+ return EDG_WLL_SSL_ERROR_ERRNO;
+ }
+ }
+ else {
+ close(sock);
+ return EDG_WLL_SSL_ERROR_ERRNO;
+ }
+ }
+
+ ctx = cred_handle->gs_ctx;
+ ssl = SSL_new(ctx);
+ if (!ssl) {
+ close(sock);
+ return EDG_WLL_SSL_ERROR_SSL;
+ }
+ SSL_set_ssl_method(ssl,SSLv3_method());
+ SSL_set_fd(ssl, sock);
+ proxy_get_filenames(NULL,1,NULL,&certdir,NULL,NULL,NULL);
+ proxy_verify_ctx_init(&verify_ctx_area);
+ proxy_verify_init(&verify_area,&verify_ctx_area);
+ SSL_set_ex_data(ssl, PVD_SSL_EX_DATA_IDX, (char *)&verify_area);
+ if (certdir!=NULL) verify_ctx_area.certdir=certdir;
+
+ if (timeout) SSL_set_mode(ssl, SSL_MODE_ENABLE_PARTIAL_WRITE);
+
+ ret = SSL_connect(ssl);
+ while (ret <= 0) {
+ int err = SSL_get_error(ssl,ret);
+ if ((err = handle_ssl_error(sock,err,timeout))) {
+ proxy_verify_release(&verify_area);
+ proxy_verify_ctx_release(&verify_ctx_area);
+ SSL_free(ssl);
+ close(sock);
+ return err;
+ }
+ ret = SSL_connect(ssl);
+ }
+ proxy_verify_release(&verify_area);
+ proxy_verify_ctx_release(&verify_ctx_area);
+ *sslp = ssl;
+ return EDG_WLL_SSL_OK;
+}
+
+SSL *edg_wll_ssl_accept(proxy_cred_desc *cred_handle,int sock,struct timeval *timeout)
+{ SSL *ssl = NULL;
+ char *certdir=NULL;
+ SSL_CTX *sslContext;
+ int ret;
+
+
+ proxy_verify_ctx_desc verify_ctx_area;
+ proxy_verify_desc verify_area;
+
+ sslContext=cred_handle->gs_ctx;
+
+ ssl = SSL_new(sslContext);
+ if (ssl == NULL) {
+ fprintf(stderr, "SSL_new(): %s\n",
+ ERR_error_string(ERR_get_error(), NULL));
+ return(NULL);
+ }
+
+ SSL_set_ssl_method(ssl,SSLv23_method());
+ SSL_set_options(ssl,SSL_OP_NO_SSLv2|SSL_OP_NO_TLSv1);
+
+ proxy_get_filenames(NULL,1,NULL,&certdir,NULL,NULL,NULL);
+ proxy_verify_ctx_init(&verify_ctx_area);
+ proxy_verify_init(&verify_area,&verify_ctx_area);
+ SSL_set_ex_data(ssl, PVD_SSL_EX_DATA_IDX, (char *)&verify_area);
+ if (certdir!=NULL) verify_ctx_area.certdir=certdir;
+
+ SSL_set_accept_state(ssl);
+ SSL_set_fd(ssl, sock);
+
+ ret = SSL_accept(ssl);
+ while (ret <= 0) {
+ int err = SSL_get_error(ssl,ret);
+ if ((err = handle_ssl_error(sock,err,timeout))) {
+ proxy_verify_release(&verify_area);
+ proxy_verify_ctx_release(&verify_ctx_area);
+ SSL_free(ssl);
+ return (NULL);
+ }
+ ret = SSL_accept(ssl);
+ }
+
+ proxy_verify_release(&verify_area);
+ proxy_verify_ctx_release(&verify_ctx_area);
+
+ return(ssl);
+}
+
+void edg_wll_ssl_reject(proxy_cred_desc *cred_handle,int sock)
+{ SSL *ssl = NULL;
+ SSL_CTX *sslContext;
+
+ sslContext=cred_handle->gs_ctx;
+
+ ssl = SSL_new(sslContext);
+ if (ssl == NULL) {
+ fprintf(stderr, "SSL_new(): %s\n",
+ ERR_error_string(ERR_get_error(), NULL));
+ return;
+ }
+
+ SSL_set_ssl_method(ssl,SSLv23_method());
+ SSL_set_options(ssl,SSL_OP_NO_SSLv2|SSL_OP_NO_TLSv1);
+
+ SSL_set_accept_state(ssl);
+ SSL_set_fd(ssl, sock);
+
+ SSL_shutdown(ssl);
+ SSL_free(ssl);
+
+ return;
+}
+
+int edg_wll_ssl_close_timeout(SSL *ssl, struct timeval *timeout)
+{
+ int ret, sock;
+
+ if (!ssl) return(0);
+ sock = SSL_get_fd(ssl);
+ ret = SSL_shutdown(ssl);
+ while (ret <= 0) {
+ int err = SSL_get_error(ssl, ret);
+ if (ret == 0 && err == SSL_ERROR_SYSCALL) {
+ /* translate misleading error returned by SSL_shutdown() to correct one */
+ switch (errno) {
+ case 0: goto closed; break;
+ case EAGAIN: err = SSL_ERROR_WANT_READ; break;
+ default: /* obey err */ break;
+ }
+ }
+ if (handle_ssl_error(sock, err, timeout))
+ break;
+ ret = SSL_shutdown(ssl);
+ }
+
+closed:
+ ret = SSL_clear(ssl);
+ ret = close(sock);
+ SSL_free(ssl);
+
+ return(0);
+}
+
+int edg_wll_ssl_close(SSL *ssl)
+{
+ struct timeval timeout = {120, 0};
+ return edg_wll_ssl_close_timeout(ssl, &timeout);
+}
+
+int edg_wll_ssl_read(SSL *ssl,void *buf,size_t bufsize,struct timeval *timeout)
+{
+ int len = 0;
+ int sock = SSL_get_fd(ssl);
+
+ len = SSL_read(ssl,buf,bufsize);
+ while (len <= 0) {
+ int err = SSL_get_error(ssl,len);
+ if ((err = handle_ssl_error(sock,err,timeout))) return err;
+ len = SSL_read(ssl,buf,bufsize);
+ }
+ return len;
+}
+
+int edg_wll_ssl_write(SSL *ssl,const void *buf,size_t bufsize,struct timeval *timeout)
+{
+ int len = 0;
+ int sock = SSL_get_fd(ssl);
+
+ len = SSL_write(ssl,buf,bufsize);
+ while (len <= 0) {
+ int err = SSL_get_error(ssl,len);
+ if ((err = handle_ssl_error(sock,err,timeout))) return err;
+ len = SSL_write(ssl,buf,bufsize);
+ }
+ return len;
+}
+
+int edg_wll_ssl_read_full(SSL *ssl,void *buf,size_t bufsize,struct timeval *timeout,size_t *total)
+{
+ int len;
+ *total = 0;
+
+ while (*total < bufsize) {
+ len = edg_wll_ssl_read(ssl,buf+*total,bufsize-*total,timeout);
+ if (len < 0) return len;
+ *total += len;
+ }
+ return 0;
+}
+
+int edg_wll_ssl_write_full(SSL *ssl,const void *buf,size_t bufsize,struct timeval *timeout,size_t *total)
+{
+ int len;
+ *total = 0;
+
+ while (*total < bufsize) {
+ len = edg_wll_ssl_write(ssl,buf+*total,bufsize-*total,timeout);
+ if (len < 0) return len;
+ *total += len;
+ }
+ return 0;
+}
+
+static int handle_ssl_error(int sock,int err,struct timeval *to)
+{
+ struct timeval timeout,before,after;
+ fd_set fds;
+ int ret = EDG_WLL_SSL_OK;
+ int saved_errno = errno;
+
+ if (to) {
+ memcpy(&timeout,to,sizeof timeout);
+ gettimeofday(&before,NULL);
+ }
+ switch (err) {
+ case SSL_ERROR_ZERO_RETURN:
+ ret = EDG_WLL_SSL_ERROR_EOF;
+ break;
+ case SSL_ERROR_WANT_READ:
+ FD_ZERO(&fds);
+ FD_SET(sock,&fds);
+ switch (select(sock+1,&fds,NULL,NULL,to?&timeout:NULL)){
+ case 0: ret = EDG_WLL_SSL_ERROR_TIMEOUT;
+ break;
+ case -1: ret = EDG_WLL_SSL_ERROR_ERRNO;
+ break;
+ }
+ break;
+ case SSL_ERROR_WANT_WRITE:
+ FD_ZERO(&fds);
+ FD_SET(sock,&fds);
+ switch (select(sock+1,NULL,&fds,NULL,to?&timeout:NULL)){
+ case 0: ret = EDG_WLL_SSL_ERROR_TIMEOUT;
+ break;
+ case -1: ret = EDG_WLL_SSL_ERROR_ERRNO;
+ break;
+ }
+ break;
+ case SSL_ERROR_SYSCALL:
+ if (saved_errno == 0) ret = EDG_WLL_SSL_ERROR_EOF;
+ else ret = EDG_WLL_SSL_ERROR_ERRNO;
+ break;
+ case SSL_ERROR_SSL:
+ ret = EDG_WLL_SSL_ERROR_SSL;
+ break;
+ default:
+ fprintf(stderr,"unexpected SSL_get_error code %d\n",err);
+ abort();
+ }
+ if (to) {
+ gettimeofday(&after,NULL);
+ tv_sub(after,before);
+ tv_sub(*to,after);
+ if (to->tv_sec < 0) {
+ to->tv_sec = 0;
+ to->tv_usec = 0;
+ }
+ }
+
+ return ret;
+}
+
+/* XXX: I'm afraid the contents of stuct stat is somewhat OS dependent */
+
+int edg_wll_ssl_watch_creds(
+ const char *key_file,
+ const char *cert_file,
+ time_t *key_mtime,
+ time_t *cert_mtime)
+{
+ struct stat kstat,cstat;
+ int reload = 0;
+
+ if (!key_file || !cert_file) return 0;
+ if (stat(key_file,&kstat) || stat(cert_file,&cstat)) return -1;
+
+ if (!*key_mtime) *key_mtime = kstat.st_mtime;
+ if (!*cert_mtime) *cert_mtime = cstat.st_mtime;
+
+ if (*key_mtime != kstat.st_mtime) {
+ *key_mtime = kstat.st_mtime;
+ reload = 1;
+ }
+
+ if (*cert_mtime != cstat.st_mtime) {
+ *cert_mtime = cstat.st_mtime;
+ reload = 1;
+ }
+
+ return reload;
+}
--- /dev/null
+#ident "$Header$"
+
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include <ctype.h>
+
+#include "ulm_parse.h"
+#include "escape.h"
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * \fn char *edg_wll_LogEscape(const char *str)
+ * \param str a string to escape
+ * \return new (allocated) escaped string
+ * \brief in given string escape all ULM_QM, ULM_BS and ULM_LF by ULM_BS
+ *
+ * Calls: malloc, strlen
+ *
+ * Algorithm: array lookup
+ * - the new string will be allocated
+ *
+ *----------------------------------------------------------------------
+ */
+
+char *edg_wll_LogEscape(const char *str)
+{
+unsigned int i,j;
+size_t size;
+char *ret;
+
+if (str == NULL) return NULL;
+if ((size = strlen(str)) == 0) return strdup("");
+
+ret = (char*) malloc(1+2*size*sizeof(char));
+
+j = 0;
+for (i=0; i<size; i++) {
+ if ((str[i] != ULM_BS) && (str[i] != ULM_QM) && (str[i] != ULM_LF)) {
+ ret[j] = str[i];
+ j++;
+ }
+ else {
+ ret[j] = ULM_BS;
+ if (str[i] == ULM_LF) {
+ ret[j+1] = 'n';
+ }
+ else {
+ ret[j+1] = str[i];
+ }
+ j += 2;
+ }
+} /* for */
+
+ret[j] = 0;
+
+return ret;
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * \fn char *edg_wll_LogUnescape(const char *str)
+ * \param str a string to unescape
+ * \return new (allocated) unescaped string
+ * \brief in given string unescape all escaped ULM_QM, ULM_BS and ULM_LF
+ *
+ * Calls: malloc, strlen
+ *
+ * Algorithm: array lookup
+ * - the new string will be allocated
+ *
+ *----------------------------------------------------------------------
+ */
+
+char *edg_wll_LogUnescape(const char *str)
+{
+unsigned int i,j;
+size_t size;
+char *ret;
+
+if (str == NULL) return NULL;
+
+size = strlen(str);
+ret = (char*) malloc(1+size*sizeof(char));
+
+/*
+j = 0;
+for (i=0; i<size; i++) {
+ if ( (str[i] != ULM_BS) ||
+ ((str[i] == ULM_BS) && ((str[i+1] != ULM_BS) && (str[i+1] != ULM_QM) && (str[i+1] != 'n'))) )
+ {
+ if (str[i] == ULM_LF) { ret[j] = 'n'; }
+ else { ret[j] = str[i]; }
+ j++;
+ }
+}
+*/
+for (i=j=0; i<size; i++,j++)
+ if (str[i] == ULM_BS) switch(str[++i]) {
+ case 'n': ret[j] = ULM_LF; break;
+ default: ret[j] = str[i]; break;
+ } else { ret[j] = str[i]; }
+
+ret[j] = '\0';
+
+return ret;
+}
+
+static const struct {
+ const char c,*e;
+} xml_etab[] = {
+ { '<',"lt" },
+ { '>',"gt" },
+ { '&',"amp" },
+ { '"',"quot" },
+ { '\'',"apos" },
+ { 0, NULL }
+};
+
+#define XML_ESCAPE_SET "<>&\"'"
+
+char *edg_wll_EscapeXML(const char *in)
+{
+ const char* tmp_in;
+ char *out;
+ int cnt,i,j,k;
+
+ if (!in) return NULL;
+
+ for (cnt = 0, tmp_in = in; *tmp_in != '\0'; ++tmp_in) {
+ if (strchr(XML_ESCAPE_SET, *tmp_in) ||
+ (*tmp_in & 0x7f) < 0x20 /* control character */ ||
+ (*tmp_in == '%')) cnt++;
+ }
+
+ out = malloc(strlen(in)+1+cnt*5);
+
+ for (i=j=0; in[i]; i++) {
+ for (k=0; xml_etab[k].c && xml_etab[k].c != in[i]; k++);
+ if (xml_etab[k].c) {
+ int l;
+
+ out[j++] = '&';
+ memcpy(out+j,xml_etab[k].e,l=strlen(xml_etab[k].e));
+ j += l;
+ out[j++] = ';';
+ } else if ((in[i] & 0x7f) < 0x20 || in[i] == '%') {
+ sprintf(out+j, "%%%02x", (unsigned char)in[i]);
+ j+=3;
+ } else {
+ out[j++] = in[i];
+ }
+ }
+ out[j] = 0;
+ return out;
+}
+
+char *edg_wll_UnescapeXML(const char *in)
+{
+ char *out;
+ int i,j,k;
+ char xtmp[3];
+ unsigned char origchar;
+
+ if (!in) return NULL;
+ out = malloc(strlen(in)+1);
+
+ for (i=j=0; in[i]; j++) if (in[i] == '&') {
+ char *s = strchr(in+i,';');
+ if (s) {
+ int l = s-in-i+1;
+ for (k=0; xml_etab[k].c && strncasecmp(in+i+1,xml_etab[k].e,l-2); k++);
+ if (xml_etab[k].c) {
+ out[j] = xml_etab[k].c;
+ i += l;
+ } else out[j] = in[i++];
+ } else out[j] = in[i++];
+ } else if (in[i] == '%') {
+ if (isxdigit(xtmp[0]=in[i+1]) && isxdigit(xtmp[1]=in[i+2])) {
+ xtmp[2] = '\0';
+ origchar = (unsigned char) strtol(xtmp, NULL, 16);
+ if ((origchar & 0x7f) < 0x20 || origchar == '%') {
+ out[j] = origchar;
+ i += 3;
+ } else out[j] = in[i++];
+ } else out[j] = in[i++];
+ } else {
+ out[j] = in[i++];
+ }
+ out[j] = 0;
+ return out;
+}
+
+char *edg_wll_EscapeSQL(const char *in)
+{
+ const char* tmp_in;
+ char *out = NULL;
+ int i,j,cnt;
+
+ if (!in) return NULL;
+
+ for (cnt = 0, tmp_in = in; (tmp_in = strchr(tmp_in,'\'')) != NULL; ++tmp_in) {
+ ++cnt;
+ }
+ for (tmp_in = in; (tmp_in = strchr(tmp_in,'\\')) != NULL; ++tmp_in) {
+ ++cnt;
+ }
+
+ out = malloc(strlen(in)+1+cnt);
+
+ for (i=j=0; in[i]; i++) {
+ if (in[i] == '\\') out[j++] = '\\';
+ if (in[i] == '\'') out[j++] = '\'';
+ out[j++] = in[i];
+ }
+ out[j] = 0;
+
+ return out;
+}
--- /dev/null
+#ident "$Header$"
+/*
+@@@AUTO
+*/
+@@@LANG: C
+
+#include <string.h>
+#include <stdlib.h>
+#include <time.h>
+#include <errno.h>
+
+#include "glite/wms/jobid/cjobid.h"
+#include "glite/lb/producer.h"
+#include "ulm_parse.h"
+
+static const struct timeval null_timeval = {0,0};
+
+/**
+ * Predefined event types names
+ */
+static const char *eventNames[] = {
+ "Undefined",
+@@@{
+for my $e (sort { $event->{order}->{$a} <=> $event->{order}->{$b} }
+ $event->getTypes) {
+ gen "\t\"$e\",\n";
+}
+@@@}
+ "SysCmpStat",
+ "SysClStat",
+};
+
+/**
+ * \fn edg_wll_EventCode edg_wll_StringToEvent(char *name)
+ * \param name a string event name (e.g. "JobTransfer")
+ * \return corresponding numeric code (edg_wll_EventCode)
+ * \brief convert a string event name to the corresponding numeric code
+ * Calls: strcasecmp
+ * Algorithm: array lookup
+ */
+edg_wll_EventCode edg_wll_StringToEvent(char *name)
+{
+ unsigned int i;
+
+ for (i=1; i<sizeof(eventNames)/sizeof(eventNames[0]); i++)
+ if (strcasecmp(eventNames[i],name) == 0) return (edg_wll_EventCode) i;
+ return EDG_WLL_EVENT_UNDEF;
+}
+
+/**
+ * \fn char *edg_wll_EventToString(edg_wll_EventCode event)
+ * \param event an event numeric code (edg_wll_EventCode)
+ * \return corresponding string (e.g. "JobTransfer")
+ * \brief convert an event numeric code to the corresponding string
+ * Calls: strdup
+ */
+char *edg_wll_EventToString(edg_wll_EventCode event)
+{
+ if ((int)event < 0 || event >= sizeof(eventNames)/sizeof(eventNames[0])) return NULL;
+ return strdup(eventNames[event]);
+}
+
+
+/**
+ * Predefined ULM key types names
+ */
+static const char *keyNames[] = {
+ "Undefined",
+ "DG.EVNT",
+@@@{
+selectType $event '_common_';
+for ($event->getFieldsOrdered) {
+ my $f = selectField $event $_;
+ my $fn = getName $f 'ULM';
+ my $fnu = uc $fn;
+ my $c = $f->{comment};
+ if (hasAlias $f 'ULM') {
+ gen "\t\"$fnu\",\n";
+ } else {
+ gen "\t\"DG.$fnu\",\n";
+ }
+}
+for my $t (sort { $event->{order}->{$a} <=> $event->{order}->{$b} }
+ $event->getTypes) {
+ my $tu = uc $t;
+ selectType $event $t;
+ for ($event->getFieldsOrdered) {
+ my $f = selectField $event $_;
+ my $fnu = uc $f->{name};
+ gen "\t\"DG.$tu.$fnu\",\n";
+ }
+}
+@@@}
+ "DG.TYPE",
+};
+
+/*
+ * \fn edg_wll_KeyNameCode edg_wll_StringToKeyName(char *name)
+ * \param name a string ULM key name (e.g. "DG.JOB.TRANSFER.DEST")
+ * \return corresponding numeric code (edg_wll_KeyNameCode)
+ * \brief convert a string ULM key name to the corresponding numeric code
+ * Calls: strcasecmp
+ * Algorithm: array lookup
+ */
+edg_wll_KeyNameCode edg_wll_StringToKeyName(char *name)
+{
+ unsigned int i;
+
+ for (i=1; i<sizeof(keyNames)/sizeof(keyNames[0]); i++)
+ if (strcasecmp(keyNames[i],name) == 0) return (edg_wll_KeyNameCode) i;
+ return UNDEFINED;
+}
+
+/*
+ * \fn char *edg_wll_KeyNameToString(edg_wll_KeyNameCode key)
+ * \param key a ULM key name numeric code (edg_wll_KeyNameCode)
+ * \return corresponding string (e.g. "DG.JOB.TRANSFER.DEST")
+ * \brief convert a ULM key name numeric code to the corresponding string
+ * Calls: strdup
+ */
+char *edg_wll_KeyNameToString(edg_wll_KeyNameCode key)
+{
+ if ((int)key < 0 || key >= sizeof(keyNames)/sizeof(keyNames[0])) return NULL;
+ return strdup(keyNames[key]);
+}
+
+
+/**
+ * Predefined _code_ types names and
+ * related StringTo_code and _code_ToString function implementations
+ */
+@@@{
+$indent = "\t";
+selectType $event '_common_';
+for ($event->getFieldsOrdered) {
+ my $f = selectField $event $_;
+ if ($f->{codes}) {
+ my $fn = ucfirst($f->{name});
+ my $fnu = uc $fn;
+ my $c = "${fn}"; # code
+ my $enum = "enum edg_wll\_$c"; # enum name
+ my $char = "edg_wll\_${fn}Names"; # char name
+# static const char:
+ gen qq{
+/**
+ * Predefined code names for $c
+ */
+static const char \*${char}\[\] = \{
+};
+ gen $indent."\"UNDEFINED\",\n";
+ for (@{$f->{codes}}) {
+ gen $indent."\"$_->{name}\",\n";
+ }
+ gen "}; \n";
+
+# function StringTo:
+ gen qq{
+/**
+ * \\fn $enum edg_wll_StringTo${c}(char *name)
+ * Calls: strcasecmp
+ * Algorithm: array lookup
+ */
+$enum edg_wll_StringTo${c}(char *name)
+\{
+ unsigned int i;
+
+ for (i=1; i<sizeof($char)/sizeof(${char}\[0\]); i++)
+ if (strcasecmp(${char}\[i\],name) == 0) return ($enum) i;
+ return ($enum) EDG_WLL_${fnu}_UNDEFINED;
+\}
+\n};
+
+# function ToString:
+ gen qq{
+/**
+ * \\fn *edg_wll\_${c}ToString($enum code)
+ * Calls: strdup
+ */
+char *edg_wll\_${c}ToString($enum code)
+\{
+ if ((int)code < 0 || code >= sizeof($char)/sizeof(${char}\[0\])) return NULL;
+ return strdup(${char}\[code\]);
+
+\}
+\n\n};
+ }
+}
+for my $t (sort { $event->{order}->{$a} <=> $event->{order}->{$b} }
+ $event->getTypes) {
+ my $tu = uc $t . '_';
+ selectType $event $t;
+ for ($event->getFieldsOrdered) {
+ my $f = selectField $event $_;
+ if ($f->{codes}) {
+ my $fn = ucfirst($f->{name});
+ my $c = "$t${fn}"; # code
+ my $enum = "enum edg_wll\_$c"; # enum name
+ my $char = "edg_wll\_$t${fn}Names"; # char name
+# static const char:
+ gen qq{
+/**
+ * Predefined code names for $c
+ */
+static const char \*${char}\[\] = \{
+};
+ gen $indent."\"UNDEFINED\",\n";
+ for (@{$f->{codes}}) {
+ gen $indent."\"$_->{name}\",\n";
+ }
+ gen "}; \n";
+
+# function StringTo:
+ gen qq{
+/**
+ * \\fn $enum edg_wll_StringTo${c}(char *name)
+ * Calls: strcasecmp
+ * Algorithm: array lookup
+ */
+$enum edg_wll_StringTo${c}(char *name)
+\{
+ unsigned int i;
+
+ for (i=1; i<sizeof($char)/sizeof(${char}\[0\]); i++)
+ if (strcasecmp(${char}\[i\],name) == 0) return ($enum) i;
+ return ($enum) EDG_WLL_${tu}UNDEFINED;
+\}
+\n};
+
+# function ToString:
+ gen qq{
+/**
+ * \\fn *edg_wll\_${c}ToString($enum code)
+ * Calls: strdup
+ */
+char *edg_wll\_${c}ToString($enum code)
+\{
+ if ((int)code < 0 || code >= sizeof($char)/sizeof(${char}\[0\])) return NULL;
+ return strdup(${char}\[code\]);
+
+\}
+\n\n};
+ }
+ }
+}
+@@@}
+
+/**
+ * Initialise an event structure
+ * \return pointer to initialised event structure
+ */
+edg_wll_Event *edg_wll_InitEvent(
+ edg_wll_EventCode eventcode /* eventcode IN */
+)
+{
+edg_wll_Event *event;
+
+/* allocate memory for 'event' (edg_wll_Event); use calloc to also clean it */
+/* FIXME: what if calloc fails? should be checked somehow -> nomem etc. */
+ event = (edg_wll_Event *) calloc(1,sizeof(edg_wll_Event));
+/* initialize common fields */
+@@@{
+$indent = "\t";
+selectType $event '_common_';
+for ($event->getFieldsOrdered) {
+ my $f = selectField $event $_;
+ my $fn = $f->getName;
+ my $fd = $f->getDefaultNullValue;
+ gen $indent."event->any.$fn = $fd;\n"
+}
+@@@}
+/* initialize dependent fields */
+switch (eventcode) {
+@@@{
+$indent = " ";
+for my $t (sort { $event->{order}->{$a} <=> $event->{order}->{$b} }
+ $event->getTypes) {
+ my $tu = uc $t;
+ my $tl = lcfirst $t;
+ gen $indent."case EDG_WLL_EVENT_$tu : \n";
+ selectType $event $t;
+ for ($event->getFieldsOrdered) {
+ my $f = selectField $event $_;
+ my $fn = $f->getName;
+ my $fd = $f->getDefaultNullValue;
+ gen $indent."\tevent->$tl.$fn = $fd;\n"
+ }
+ gen $indent.$indent."break;\n";
+}
+@@@}
+ case EDG_WLL_EVENT_UNDEF :
+ default :
+ break;
+}
+return event;
+}
+
+/**
+ * edg_wll_FreeEvent
+ * \brief free memory allocated for edg_wll_Event internal fields
+ * Calls: free
+ */
+void edg_wll_FreeEvent(
+ edg_wll_Event *event /* event IN */
+)
+{
+edg_wll_EventCode eventcode=event->type;
+
+/* free the common fields */
+ if (event->any.jobId) edg_wlc_JobIdFree(event->any.jobId);
+@@@{
+$indent = "\t";
+selectType $event '_common_';
+for ($event->getFieldsOrdered) {
+ my $f = selectField $event $_;
+ my $fn = $f->{name};
+ my $ft = $f->{type};
+ if ($ft eq 'string') {
+ gen $indent."if (event->any.$fn) free(event->any.$fn);\n"
+ }
+}
+@@@}
+
+/* free the rest */
+switch (eventcode) {
+@@@{
+$indent = " ";
+for my $t (sort { $event->{order}->{$a} <=> $event->{order}->{$b} }
+ $event->getTypes) {
+ my $tu = uc $t;
+ my $tl = lcfirst $t;
+ gen $indent."case EDG_WLL_EVENT_$tu :\n";
+ selectType $event $t;
+ for ($event->getFieldsOrdered) {
+ my $f = selectField $event $_;
+ my $fn = $f->{name};
+ my $ft = $f->{type};
+ if ($ft eq 'string') {
+ gen $indent."\tif (event->$tl.$fn) free(event->$tl.$fn);\n"
+ }
+ }
+ gen $indent.$indent."break;\n"
+}
+@@@}
+ case EDG_WLL_EVENT_UNDEF :
+ default:
+ break;
+}
+
+}
--- /dev/null
+#ident "$Header$"
+/*
+@@@AUTO
+*/
+@@@LANG: C
+
+#include <string.h>
+#include <stdlib.h>
+#include <time.h>
+#include <errno.h>
+
+#include "glite/lb/events.h"
+#include "glite/lb/producer.h"
+#include "events_parse.h"
+#include "ulm_parse.h"
+#include "context-int.h"
+#include "escape.h"
+#include "glite/wms/jobid/cjobid.h"
+
+#include "glite/lb/trio.h"
+
+static const struct timeval null_timeval = {0,0};
+
+/* -- Internal function prototype -- */
+char *my_edg_wll_ULMGetValueAt( p_edg_wll_ULMFields, int );
+
+/**
+ * edg_wll_ParseEvent - parse ULM message to internal structures
+ * Calls: calloc, free, sprintf, strdup
+ * edg_wll_ULMNewParseTable, edg_wll_ULMFreeParseTable, edg_wll_ULMProcessParseTable,
+ * edg_wll_ULMGetNameAt, my_edg_wll_ULMGetValueAt, edg_wll_ULMDateToTimeval (edg_wll_ULMDateToDouble),
+ * edg_wll_StringToEvent, edg_wll_StringToKeyName, edg_wll_StringToLevel, edg_wlc_jobid_tParse,
+ * edg_wll_EventToString, edg_wll_KeyNameToString, edg_wll_SetError (or edg_wll_ResetError)
+ * Algorithm: break ULM string into fields and then according the event type
+ * fill in the proper structures
+ */
+
+#define DUPLICITY { \
+ char *k = edg_wll_KeyNameToString(keycode); \
+ sprintf(err_desc,"Key %s already exists.", k); \
+ free(k); \
+ ret=edg_wll_SetError(context,EDG_WLL_ERROR_PARSE_KEY_DUPLICITY,err_desc); \
+ goto end; }
+
+#define MISUSE { \
+ char *e = edg_wll_EventToString(eventcode); \
+ char *k = edg_wll_KeyNameToString(keycode); \
+ sprintf(err_desc,"Key %s schouldn't be used for event type %s.", k,e); \
+ free(e); \
+ free(k); \
+ ret=edg_wll_SetError(context,EDG_WLL_ERROR_PARSE_KEY_MISUSE,err_desc); \
+ goto end; }
+
+edg_wll_ErrorCode edg_wll_ParseEvent(
+ edg_wll_Context context, /* context IN */
+ edg_wll_LogLine logline, /* logline IN: ULM string to parse */
+ edg_wll_Event **event /* event OUT: parsed event
+ (may be NULL - syntax checking with no output */
+)
+{
+int i;
+int extra=0; /* number of extra unknown key=value pairs */
+char err_desc[128]; /* error description for use in edg_wll_SetError */
+char *value=NULL;
+p_edg_wll_ULMFields table = edg_wll_ULMNewParseTable(logline);
+edg_wll_KeyNameCode keycode=UNDEFINED;
+edg_wll_EventCode eventcode=EDG_WLL_EVENT_UNDEF;
+edg_wll_ErrorCode ret;
+edg_wll_Event *this=NULL;
+
+/* break ULM string into fields */
+if ( edg_wll_ULMProcessParseTable(table) != 0 ) {
+ ret=edg_wll_SetError(context,EDG_WLL_ERROR_PARSE_BROKEN_ULM,"ULM parse error");
+ goto end;
+}
+
+/* determine the event type */
+for (i=0; i<table->num; i++) {
+ keycode=edg_wll_StringToKeyName(edg_wll_ULMGetNameAt(table,i));
+ if ( keycode == EDG_WLL_EVNT ) {
+ value=my_edg_wll_ULMGetValueAt(table,i);
+ eventcode=edg_wll_StringToEvent(value);
+ free(value);
+ value=NULL;
+ break;
+ }
+}
+if ( eventcode == EDG_WLL_EVENT_UNDEF ) {
+ ret=edg_wll_SetError(context,EDG_WLL_ERROR_PARSE_EVENT_UNDEF,"Unknown or missing event type");
+ goto end;
+}
+/* allocate memory for 'this' (edg_wll_Event) */
+// XXX: this = (edg_wll_Event *) calloc(1,sizeof(edg_wll_Event));
+this = edg_wll_InitEvent(eventcode);
+this->any.type = eventcode;
+
+/* go through all fields and fill in the edg_wll_Event union
+ * in each step check for key duplicity and key name misuse
+ */
+for (i=0; i<table->num; i++) {
+ keycode=edg_wll_StringToKeyName(edg_wll_ULMGetNameAt(table,i));
+ value=my_edg_wll_ULMGetValueAt(table,i);
+ switch (keycode) {
+ case EDG_WLL_EVNT :
+ if (this->any.type != edg_wll_StringToEvent(value)) DUPLICITY
+ break;
+@@@{
+$indent = " ";
+selectType $event '_common_';
+for ($event->getFieldsOrdered) {
+ my $f = selectField $event $_;
+ my $fn = getName $f;
+ my $fnu = uc getName $f 'ULM';
+ if (hasAlias $f 'ULM') {
+ gen $indent."case ULM\_$fnu :\n";
+ } else {
+ gen $indent."case EDG_WLL\_COMMON\_$fnu :\n";
+ }
+ gen "\tif (";
+ gen $f->isnotNULL("this->any.$fn");
+ gen ") DUPLICITY \n";
+ gen "\t";
+ if ($f->{codes}) {
+ my $c = ucfirst(${fn});
+ gen "this->any.$fn = edg_wll_StringTo${c}(value);";
+ } else {
+ gen $f->fromString('value',"this->any.$fn");
+ }
+ gen "\n".$indent.$indent."break;\n";
+}
+for my $t (sort { $event->{order}->{$a} <=> $event->{order}->{$b} }
+ $event->getTypes) {
+ my $tu = uc $t;
+ my $tl = lcfirst $t;
+ my $misuse = "if (eventcode != EDG_WLL_EVENT_$tu ) MISUSE";
+ selectType $event $t;
+ for ($event->getFieldsOrdered) {
+ my $f = selectField $event $_;
+ my $fn = $f->{name};
+ my $fnu = uc $fn;
+ gen $indent."case EDG_WLL\_$tu\_$fnu :\n";
+ gen "\tif (";
+ gen $f->isnotNULL("this->$tl.$fn");
+ gen ") DUPLICITY\n";
+ gen "\t$misuse\n";
+ if ($f->{codes}) {
+ my $c = "$t".ucfirst(${fn});
+ gen "\tthis->$tl.$fn = edg_wll_StringTo${c}(value);";
+ } else {
+ gen "\t";
+ gen $f->fromString('value',"this->$tl.$fn");
+ }
+ gen "\n".$indent.$indent."break;\n";
+ }
+}
+@@@}
+
+ case UNDEFINED :
+ case EDG_WLL_INTERNAL_TYPE :
+ break;
+
+ default :
+ extra++;
+ break;
+ }
+ free(value);
+ value=NULL;
+}
+
+/* now check if all required fields are present */
+ret=edg_wll_CheckEvent(context,this);
+if (ret) { goto end; }
+
+/* parse is OK, only extra fields could occur */
+if (extra) {
+ sprintf(err_desc,"There are %d extra fields in the logline.",extra);
+ ret=edg_wll_SetError(context,EDG_WLL_ERROR_PARSE_OK_WITH_EXTRA_FIELDS,err_desc); }
+else { ret=edg_wll_ResetError(context); }
+
+end:
+ /* finally (if wanted) "return" pointer to the filled edg_wll_Event union
+ NOTE: a pointer (to half-filled structure) is returned even if an error occured ! */
+ if (event != NULL) {
+ *event = this; }
+ /* This also means, that the memory must be freed by edg_wll_FreeEvent() somewhere else */
+ else {
+ edg_wll_FreeEvent(this);
+ free(this);
+ }
+
+ edg_wll_ULMFreeParseTable(table);
+ return ret;
+}
+
+/**
+ * edg_wll_UnparseEvent - unparse ULM message from internal structures
+ * Calls: malloc, free, strlen, strcmp, asprintf, trio_asprintf
+ * edg_wll_ULMTimevalToDate,
+ * edg_wll_EventToString, edg_wll_KeyNameToString, edg_wll_LevelToString,
+ * edg_wlc_jobid_tUnparse,
+ * Algorithm: format values from internal structures into a ULM string
+ */
+#define NOMEM { if (logline) free(logline); logline = NULL; edg_wll_SetError(context,ENOMEM,NULL); goto clean; }
+
+edg_wll_LogLine edg_wll_UnparseEvent( /* logline OUT */
+ edg_wll_Context context, /* context IN */
+ edg_wll_Event *event /* event IN */
+)
+{
+edg_wll_LogLine logline;
+edg_wll_EventCode eventcode=event->type;
+char *date, *common, *user, *var, *e, *l, *j, *s;
+edg_wll_Event nonulls;
+
+logline = date = common = user = var = NULL;
+
+/* FIXME: after EDG_WLL_FORMAT_COMMON automatic generation automate this code as well */
+/* format the common fields */
+date=(char *) malloc(1+ULM_DATE_STRING_LENGTH*sizeof(char));
+edg_wll_ULMTimevalToDate(event->any.timestamp.tv_sec, event->any.timestamp.tv_usec, date);
+
+memcpy(&nonulls,event,sizeof nonulls);
+@@@{
+ selectType $event '_common_';
+ for ($event->getFieldsOrdered) {
+ my $f = selectField $event $_;
+ my $fn = $f->{name};
+ gen "if (!nonulls.any.$fn) nonulls.any.$fn = \"\";\n"
+ if $f->{type} eq 'string';
+ }
+@@@}
+
+e = edg_wll_EventToString(eventcode);
+l = edg_wll_LevelToString(event->any.level);
+j = edg_wlc_JobIdUnparse(event->any.jobId);
+s = edg_wll_SourceToString(event->any.source);
+if (trio_asprintf(&common,EDG_WLL_FORMAT_COMMON, \
+ date, event->any.host, l, event->any.priority, s, nonulls.any.src_instance, \
+ e, j, nonulls.any.seqcode) == -1) {
+ if (e) free(e);
+ if (l) free(l);
+ if (j) free(j);
+ if (s) free(s);
+ NOMEM
+}
+if (e) free(e);
+if (l) free(l);
+if (j) free(j);
+if (s) free(s);
+
+if (trio_asprintf(&user,EDG_WLL_FORMAT_USER, event->any.user) == -1) NOMEM
+
+/* format the rest of the logline */
+switch (eventcode) {
+@@@{
+$indent = " ";
+for my $t (sort { $event->{order}->{$a} <=> $event->{order}->{$b} }
+ $event->getTypes) {
+ my $tu = uc $t;
+ my $tl = lcfirst $t;
+ my $free = "";
+ gen $indent."case EDG_WLL_EVENT_$tu :\n";
+ gen "\t\{";
+ selectType $event $t;
+# if there are some _code_, convert them from string:
+ for ($event->getFieldsOrdered) {
+ my $f = selectField $event $_;
+ my $fn = $f->{name};
+ my $fnu = ucfirst $fn;
+ if ($f->{codes}) {
+ gen "\tchar \*$fn\_code = edg_wll\_$t${fnu}ToString(event->$tl.$fn);\n";
+ $free = $free . "free($fn\_code); ";
+ }
+ if ($f->{type} eq 'jobid') {
+ gen "\tchar \*$fn\_str = edg_wlc_JobIdUnparse(event->$tl.$fn);\n";
+ $free .= "free($fn\_str); ";
+ }
+ if ($f->{type} eq 'notifid') {
+ gen "\tchar \*$fn\_str = edg_wll_NotifIdUnparse(event->$tl.$fn);\n";
+ $free .= "free($fn\_str); ";
+ }
+ if ($ULMasString{$f->{type}}) {
+ gen "\tchar \*$fn\_str = ".$f->getType()."ToString(event->$tl.$fn);\n";
+ $free .= "free($fn\_str); ";
+ }
+ }
+
+ for ($event->getFieldsOrdered) {
+ my $f = selectField $event $_;
+ my $fn = $f->{name};
+
+ gen "\t\tif (!nonulls.$tl.$fn) nonulls.$tl.$fn = \"\";\n"
+ if $f->{type} eq 'string';
+ }
+ gen "\tif (trio_asprintf(&var,EDG_WLL_FORMAT_$tu";
+# now format remaining parapteres for trio_asprintf:
+ for ($event->getFieldsOrdered) {
+ my $f = selectField $event $_;
+ my $fn = $f->{name};
+ if ($f->{codes}) {
+ gen ",$fn\_code";
+ }
+ elsif ($f->{type} eq 'jobid' || $f->{type} eq 'notifid' || $ULMasString{$f->{type}}) {
+ gen ",$fn\_str?$fn\_str:\"\"";
+ } else {
+ gen ",nonulls.$tl.$fn";
+ }
+ }
+ gen ") == -1 ) \{\n";
+ gen "\t".$indent.$free."NOMEM \}\n";
+ if ($free) { gen "\t$free\n"; }
+ gen "\t\}\n";
+ gen $indent.$indent."break;\n";
+}
+@@@}
+ case EDG_WLL_EVENT_UNDEF :
+ default :
+ break;
+}
+
+/* put it all together (inc. the ending LF) */
+if (asprintf(&logline,"%s%s%s\n",common,user,var) == -1) NOMEM
+
+clean:
+ if (date) free(date);
+ if (common) free(common);
+ if (user) free(user);
+ if (var) free(var);
+ return logline;
+}
+
+
+/**
+ * edg_wll_CheckEvent - check internal structures if all required fields are present
+ * Calls: free, sprintf, strcmp
+ * edg_wll_KeyNameToString, edg_wll_SetError (or edg_wll_ResetError)
+ * Algorithm:
+ */
+#define MISSING(m_key) { \
+ char *k = edg_wll_KeyNameToString(m_key); \
+ sprintf(err_desc,"Message incomplete, missing key %s.", k); \
+ free(k); \
+ ret=edg_wll_SetError(context,EDG_WLL_ERROR_PARSE_MSG_INCOMPLETE,err_desc); \
+ goto end; }
+
+edg_wll_ErrorCode edg_wll_CheckEvent(
+ edg_wll_Context context, /* context IN */
+ edg_wll_Event *event /* event IN */
+)
+{
+char err_desc[128]; /* error description for use in edg_wll_SetError */
+edg_wll_EventCode eventcode=EDG_WLL_EVENT_UNDEF;
+edg_wll_ErrorCode ret;
+
+eventcode=event->type;
+if ( eventcode == EDG_WLL_EVENT_UNDEF ) {
+ ret=edg_wll_SetError(context,EDG_WLL_ERROR_PARSE_EVENT_UNDEF,"Unknown or missing event type");
+ goto end;
+}
+
+/*
+FIXME:
+? if (!event->any.user) MISSING(EDG_WLL_USER) - cannot use in edg_wll_LogEvent(), where is no DG.USER
+*/
+
+@@@{
+ $indent = " ";
+ selectType $event '_common_';
+ for ($event->getFieldsOrdered) {
+ my $f = selectField $event $_;
+ my $fn = $f->{name};
+ next if $f->{optional};
+ if (!$f->{codes}) {
+ if (!$f->hasAlias('ULM')) {
+ my $fu = uc $fn;
+ gen "\tif (". $f->isNULL("event->any.$fn") .") MISSING(EDG_WLL\_COMMON\_$fu)\n";
+ } else {
+ my $fa = $f->getName('ULM');
+ my $fu = uc $fa;
+ gen "\tif (". $f->isNULL("event->any.$fn") .") MISSING(ULM\_$fu)\n";
+ }
+ }
+ }
+@@@}
+
+switch (eventcode) {
+@@@{
+$indent = " ";
+for my $t (sort { $event->{order}->{$a} <=> $event->{order}->{$b} }
+ $event->getTypes) {
+ my $tu = uc $t;
+ my $tl = lcfirst $t;
+ gen $indent."case EDG_WLL_EVENT_$tu :\n";
+ selectType $event $t;
+ for ($event->getFieldsOrdered) {
+ my $f = selectField $event $_;
+ next if $f->{optional};
+ if (!$f->{codes}) {
+ my $fn = $f->{name};
+ my $fu = uc $fn;
+ my $ft = $f->{type};
+ gen "\tif (". $f->isNULL("event->$tl.$fn") .") MISSING(EDG_WLL\_$tu\_$fu)\n";
+ }
+ }
+ gen $indent.$indent."break;\n";
+}
+@@@}
+
+ case EDG_WLL_EVENT_UNDEF :
+ default:
+ ret=edg_wll_SetError(context,EDG_WLL_ERROR_PARSE_EVENT_UNDEF,"Unknown or missing event type");
+ goto end;
+ break;
+};
+ret=edg_wll_ResetError(context);
+
+end:
+ return ret;
+}
+
+
+/**
+ * my_edg_wll_ULMGetValueAt - get value at index, but also
+ * - remove surrounding quotes if any
+ * - and unescape the string
+ * - the new string will be allocated (by edg_wll_LogUnescape)
+ * Calls: edg_wll_ULMGetValueAt, edg_wll_LogUnescape, calloc and strncpy or strdup
+ */
+char *my_edg_wll_ULMGetValueAt( p_edg_wll_ULMFields table, int index )
+{
+char *str = edg_wll_ULMGetValueAt( table, index);
+size_t len = strlen(str);
+char *ret,*first,*last,*tmp;
+
+first = last = str;
+last += len - 1;
+
+/* remove surrounding quotes */
+if ((*first == ULM_QM) && (*last == ULM_QM)) {
+ /* be careful with doppel_ULM_QM */
+ if (len > 2) {
+ tmp = (char *) calloc (1,(len-1)*sizeof(char));
+ strncpy(tmp,first+1,len-2);
+ tmp[len-2] = '\0';
+ }
+ else {
+ tmp = strdup("");
+ }
+}
+else tmp = strdup(str);
+
+if (len > 2) {
+ ret = edg_wll_LogUnescape(tmp);
+ if (tmp) free(tmp);
+}
+else ret = tmp;
+
+return ret;
+}
+
+
+/**
+ * edg_wll_GetJobId - parse jobId from ULM message
+ * Returns: edg_wlc_jobid_t string or NULL
+ * Calls: edg_wll_ULMNewParseTable, edg_wll_ULMFreeParseTable, edg_wll_ULMProcessParseTable,
+ * edg_wll_ULMGetNameAt, my_edg_wll_ULMGetValueAt, edg_wlc_jobid_tParse, strdup
+ * Algorithm: break ULM string into fields and then look for jobId
+ */
+char *edg_wll_GetJobId(edg_wll_LogLine logline)
+{
+p_edg_wll_ULMFields table = edg_wll_ULMNewParseTable(logline);
+int i;
+char *ret=NULL,*fullid=NULL;
+edg_wll_KeyNameCode keycode=UNDEFINED;
+edg_wlc_JobId jobId = NULL;
+
+/* break ULM string into fields */
+if ( edg_wll_ULMProcessParseTable(table) != 0 ) goto clean;
+
+/* look for jobId */
+for (i=0; i<table->num; i++) {
+ keycode=edg_wll_StringToKeyName(edg_wll_ULMGetNameAt(table,i));
+ if ( keycode == EDG_WLL_COMMON_JOBID ) { fullid=my_edg_wll_ULMGetValueAt(table,i); break; }
+}
+if ( fullid == NULL ) goto clean;
+
+if (edg_wlc_JobIdParse(fullid, &jobId)) goto clean;
+
+ret = strdup(fullid);
+
+clean:
+ if (fullid) free(fullid);
+ if (jobId) edg_wlc_JobIdFree(jobId);
+ edg_wll_ULMFreeParseTable(table);
+ return ret;
+}
+
+/**
+ * Parse a special Notification ULM line into a edg_wll_Event structure
+ * \param context IN: context to work with
+ * \param logline IN: ULM string to parse
+ * \param event OUT: parsed event
+ * (may be NULL - syntax checking with no output)
+ */
+edg_wll_ErrorCode edg_wll_ParseNotifEvent(
+ edg_wll_Context context,
+ edg_wll_LogLine logline,
+ edg_wll_Event ** event
+)
+{
+int i;
+int extra=0; /* number of extra unknown key=value pairs */
+char err_desc[128]; /* error description for use in edg_wll_SetError */
+char *value=NULL;
+p_edg_wll_ULMFields table = edg_wll_ULMNewParseTable(logline);
+edg_wll_KeyNameCode keycode=UNDEFINED;
+const edg_wll_EventCode eventcode=EDG_WLL_EVENT_NOTIFICATION;
+edg_wll_ErrorCode ret;
+edg_wll_Event *this=NULL;
+
+/* break ULM string into fields */
+if ( edg_wll_ULMProcessParseTable(table) != 0 ) {
+ ret=edg_wll_SetError(context,EDG_WLL_ERROR_PARSE_BROKEN_ULM,"ULM parse error");
+ goto end;
+}
+
+/* allocate memory for 'this' (edg_wll_Event) */
+this = edg_wll_InitEvent(eventcode);
+this->any.type = eventcode;
+
+/* go through all fields and fill in the edg_wll_Event union
+ * in each step check for key duplicity and key name misuse
+ */
+for (i=0; i<table->num; i++) {
+ keycode=edg_wll_StringToKeyName(edg_wll_ULMGetNameAt(table,i));
+ value=my_edg_wll_ULMGetValueAt(table,i);
+ switch (keycode) {
+ case EDG_WLL_EVNT :
+ if (this->any.type != edg_wll_StringToEvent(value)) DUPLICITY
+ break;
+ case ULM_DATE :
+ if (!((this->any.timestamp).tv_sec == (null_timeval).tv_sec && (this->any.timestamp).tv_usec == (null_timeval).tv_usec)) DUPLICITY
+ edg_wll_ULMDateToTimeval(value,&this->any.timestamp);
+ break;
+ case ULM_ARR_DATE :
+ if (!((this->any.arrived).tv_sec == (null_timeval).tv_sec && (this->any.arrived).tv_usec == (null_timeval).tv_usec)) DUPLICITY
+ edg_wll_ULMDateToTimeval(value,&this->any.arrived);
+ break;
+ case ULM_HOST :
+ if (!(((this->any.host) == NULL && (NULL) == NULL) || ((this->any.host)&&(NULL)&& !strcmp(this->any.host,NULL)))) DUPLICITY
+ this->any.host = strdup(value);
+ break;
+ case ULM_LVL :
+ if (!((this->any.level == 0))) DUPLICITY
+ this->any.level = edg_wll_StringToLevel(value);
+ break;
+ case EDG_WLL_COMMON_SOURCE :
+ if (!((this->any.source) == (EDG_WLL_SOURCE_NONE))) DUPLICITY
+ this->any.source = edg_wll_StringToSource(value);
+ break;
+ case EDG_WLL_COMMON_SRC_INSTANCE :
+ if (!(((this->any.src_instance) == NULL && (NULL) == NULL) || ((this->any.src_instance)&&(NULL)&& !strcmp(this->any.src_instance,NULL)))) DUPLICITY
+ this->any.src_instance = strdup(value);
+ break;
+@@@{
+ $indent = " ";
+ my $t = 'Notification';
+ my $tu = uc $t;
+ my $tl = lcfirst $t;
+ my $misuse = "if (eventcode != EDG_WLL_EVENT_$tu ) MISUSE";
+ selectType $event $t;
+ for ($event->getFieldsOrdered) {
+ my $f = selectField $event $_;
+ my $fn = $f->{name};
+ my $fnu = uc $fn;
+ gen $indent."case EDG_WLL\_$tu\_$fnu :\n";
+ gen "\tif (";
+ gen $f->isnotNULL("this->$tl.$fn");
+ gen ") DUPLICITY\n";
+ gen "\t$misuse\n";
+ if ($f->{codes}) {
+ my $c = "$t".ucfirst(${fn});
+ gen "\tthis->$tl.$fn = edg_wll_StringTo${c}(value);";
+ } else {
+ gen "\t";
+ gen $f->fromString('value',"this->$tl.$fn");
+ }
+ gen "\n".$indent.$indent."break;\n";
+ }
+@@@}
+
+ case UNDEFINED :
+ case EDG_WLL_INTERNAL_TYPE :
+ break;
+
+ default :
+ extra++;
+ break;
+ }
+ free(value);
+ value=NULL;
+}
+
+/* parse is OK, only extra fields could occur */
+if (extra) {
+ sprintf(err_desc,"There are %d extra fields in the logline.",extra);
+ ret=edg_wll_SetError(context,EDG_WLL_ERROR_PARSE_OK_WITH_EXTRA_FIELDS,err_desc); }
+else { ret=edg_wll_ResetError(context); }
+
+end:
+ /* finally (if wanted) "return" pointer to the filled edg_wll_Event union
+ NOTE: a pointer (to half-filled structure) is returned even if an error occured ! */
+ if (event != NULL) {
+ *event = this; }
+ /* This also means, that the memory must be freed by edg_wll_FreeEvent() somewhere else */
+ else {
+ edg_wll_FreeEvent(this);
+ free(this);
+ }
+
+ edg_wll_ULMFreeParseTable(table);
+ return ret;
+}
+
+/**
+ * Generate a special Notification ULM line from edg_wll_Event structure
+ * \param context IN: context to work with
+ * \param event IN: event to unparse
+ */
+edg_wll_LogLine edg_wll_UnparseNotifEvent(
+ edg_wll_Context context,
+ edg_wll_Event * event
+)
+{
+edg_wll_LogLine logline;
+char *date, *common, *var, *l, *s;
+edg_wll_Event nonulls;
+
+logline = date = common = var = l = s = NULL;
+
+/* format the common fields */
+date=(char *) malloc(1+ULM_DATE_STRING_LENGTH*sizeof(char));
+edg_wll_ULMTimevalToDate(event->any.timestamp.tv_sec, event->any.timestamp.tv_usec, date);
+
+memcpy(&nonulls,event,sizeof nonulls);
+if (!nonulls.any.host) nonulls.any.host = "";
+if (!nonulls.any.src_instance) nonulls.any.src_instance = "";
+
+l = edg_wll_LevelToString(event->any.level);
+s = edg_wll_SourceToString(event->any.source);
+if (trio_asprintf(&common,EDG_WLL_FORMAT_NOTIFICATION_COMMON, \
+ date, event->any.host, l, s, nonulls.any.src_instance) == -1) {
+ if (l) free(l);
+ if (s) free(s);
+ NOMEM
+ }
+if (l) free(l);
+if (s) free(s);
+
+// n = edg_wlc_NotifIdUnparse(event->notification.notifId);
+
+/* format the rest of the logline */
+@@@{
+$indent = " ";
+ my $t = 'Notification';
+ my $tu = uc $t;
+ my $tl = lcfirst $t;
+ my $free = "";
+## gen $indent."case EDG_WLL_EVENT_$tu :\n";
+ gen "\t\{";
+ selectType $event $t;
+# if there are some _code_, convert them from string:
+ for ($event->getFieldsOrdered) {
+ my $f = selectField $event $_;
+ my $fn = $f->{name};
+ my $fnu = ucfirst $fn;
+ if ($f->{codes}) {
+ gen "\tchar \*$fn\_code = edg_wll\_$t${fnu}ToString(event->$tl.$fn);\n";
+ $free = $free . "free($fn\_code); ";
+ }
+ if ($f->{type} eq 'jobid') {
+ gen "\tchar \*$fn\_str = edg_wlc_JobIdUnparse(event->$tl.$fn);\n";
+ $free .= "free($fn\_str); ";
+ }
+ if ($f->{type} eq 'notifid') {
+ gen "\tchar \*$fn\_str = edg_wll_NotifIdUnparse(event->$tl.$fn);\n";
+ $free .= "free($fn\_str); ";
+ }
+ if ($ULMasString{$f->{type}}) {
+ gen "\tchar \*$fn\_str = ".$f->getType()."ToString(event->$tl.$fn);\n";
+ $free .= "free($fn\_str); ";
+ }
+ }
+
+ for ($event->getFieldsOrdered) {
+ my $f = selectField $event $_;
+ my $fn = $f->{name};
+
+ gen "\t\tif (!nonulls.$tl.$fn) nonulls.$tl.$fn = \"\";\n"
+ if $f->{type} eq 'string';
+ }
+ gen "\tif (trio_asprintf(&var,EDG_WLL_FORMAT_$tu";
+# now format remaining parapteres for trio_asprintf:
+ for ($event->getFieldsOrdered) {
+ my $f = selectField $event $_;
+ my $fn = $f->{name};
+ if ($f->{codes}) {
+ gen ",$fn\_code";
+ }
+ elsif ($f->{type} eq 'jobid' || $f->{type} eq 'notifid' || $ULMasString{$f->{type}}) {
+ gen ",$fn\_str?$fn\_str:\"\"";
+ } else {
+ gen ",nonulls.$tl.$fn";
+ }
+ }
+ gen ") == -1 ) \{\n";
+ gen "\t".$indent.$free."NOMEM \}\n";
+ if ($free) { gen "\t$free\n"; }
+ gen "\t\}\n";
+## gen $indent.$indent."break;\n";
+@@@}
+
+/* put it all together (inc. the ending LF) */
+if (asprintf(&logline,"%s%s\n",common,var) == -1) NOMEM
+
+clean:
+ if (date) free(date);
+ if (common) free(common);
+ if (var) free(var);
+ return logline;
+}
+
--- /dev/null
+#ident "$Header$"
+
+#include <string.h>
+#include <assert.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "il_string.h"
+
+char *
+_put_int(char *p, int d)
+{
+ char buf[32];
+ int len;
+
+ assert( p != NULL );
+
+ snprintf(buf, sizeof(buf), "%d", d);
+ len = strlen(buf);
+ strncpy(p, buf, len);
+ return(p + len);
+}
+
+
+char *
+put_int(char *p, int d)
+{
+ assert( p != NULL );
+
+ p = _put_int(p, d);
+ *p++ = '\n';
+ return(p);
+}
+
+
+char *
+_get_int(char *p, int *d)
+{
+ char *end;
+
+ assert( p != NULL );
+ assert( d != NULL );
+
+ *d = strtol(p, &end, 10);
+ return(end);
+}
+
+
+char *
+get_int(char *p, int *d)
+{
+ assert( p != NULL );
+ assert( d != NULL );
+
+ p = _get_int(p, d);
+ if(*p != '\n')
+ return(NULL);
+ else
+ return(p + 1);
+}
+
+
+int
+len_int(int d)
+{
+ char buffer[256];
+
+ return(put_int(buffer, d) - buffer);
+}
--- /dev/null
+#ident "$Header$"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <syslog.h>
+
+int log_level;
+
+int
+il_log(int level, char *fmt, ...)
+{
+ char *err_text;
+ va_list fmt_args;
+
+ va_start(fmt_args, fmt);
+ vasprintf(&err_text, fmt, fmt_args);
+ va_end(fmt_args);
+
+ if(level <= log_level)
+ fprintf(stderr, err_text);
+
+ if(level <= LOG_ERR) {
+ openlog("edg-wl-interlogd", LOG_PID | LOG_CONS, LOG_DAEMON);
+ syslog(level, "%s", err_text);
+ closelog();
+ }
+
+ if(err_text) free(err_text);
+
+ return(0);
+}
--- /dev/null
+#ident "$Header$"
+
+#include "il_string.h"
+
+#include <malloc.h>
+#include <stdio.h>
+#include <unistd.h>
+
+int
+receive_msg(int sd, char **ucs, char **event)
+{
+ char buffer[17];
+ char *p, *q, *msg;
+ int len;
+
+ len = read(sd, buffer, 17);
+
+ if(buffer[16] != '\n') {
+ printf("Error in header!\n");
+ goto err;
+ }
+
+ sscanf(buffer, "%d", &len);
+ if(len > MAXLEN) {
+ printf("Message too long!\n");
+ goto err;
+ }
+ p = msg = malloc(len+1);
+ if(p == NULL) {
+ printf("Error allocating %d bytes\n", len+1);
+ goto err;
+ }
+
+ read(sd, p, len);
+ p[len] = 0;
+
+ if((q = get_string(p, ucs)) == NULL) {
+ printf("Protocol error at %s\n", p);
+ goto err;
+ }
+ p = q;
+ if((q = get_string(p, event)) == NULL) {
+ printf("Protocol error at %s\n", p);
+ goto err;
+ }
+
+ free(msg);
+ return(0);
+
+ err:
+
+ return(-1);
+}
--- /dev/null
+#ident "$Header$"
+
+#include <string.h>
+#include <stdlib.h>
+#include <assert.h>
+
+#include "il_string.h"
+
+char *
+put_string(char *p, char *s)
+{
+ int len = strlen(s);
+
+ assert( p != NULL );
+
+ p = _put_int(p, len);
+ *p++ = ' ';
+ strncpy(p, s, len);
+ p += len;
+ *p++ = '\n';
+ return(p);
+}
+
+
+int
+len_string(char *s)
+{
+ int len, slen;
+
+ assert( s != NULL );
+
+ slen = strlen(s);
+ len = len_int(slen);
+
+ return(len + slen + 1);
+}
+
+
+char *
+get_string(char *p, char **s)
+{
+ int len;
+
+ assert( p != NULL );
+
+ *s = NULL;
+
+ p = _get_int(p, &len);
+ if(*p != ' ')
+ return(NULL);
+ else
+ {
+ *s = malloc(len + 1);
+ if(*s == NULL)
+ return(NULL);
+ strncpy(*s, ++p, len);
+ (*s)[len] = '\0';
+ p += len;
+ return( *p++ == '\n' ? p : NULL );
+ }
+}
--- /dev/null
+#ident "$Header$"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <unistd.h>
+#include <signal.h>
+#include <assert.h>
+#include <fcntl.h>
+#include <syslog.h>
+
+#include "globus_config.h"
+#include "glite/wms/thirdparty/globus_ssl_utils/sslutils.h"
+
+#include "mini_http.h"
+#include "dgssl.h"
+#include "context-int.h"
+
+#define min(x,y) ((x) < (y) ? (x) : (y))
+#define CONTENT_LENGTH "Content-Length:"
+
+edg_wll_ErrorCode edg_wll_http_recv(edg_wll_Context ctx,char **firstOut,char ***hdrOut,char **bodyOut)
+{
+ char **hdr = NULL,*first = NULL,*body = NULL;
+ enum { FIRST, HEAD, BODY, DONE } pstat = FIRST;
+ int len, nhdr = 0,rdmore = 0,clen = 0,blen = 0;
+ int sock;
+
+#define bshift(shift) {\
+ memmove(ctx->connPool[ctx->connToUse].buf,ctx->connPool[ctx->connToUse].buf+(shift),ctx->connPool[ctx->connToUse].bufUse-(shift));\
+ ctx->connPool[ctx->connToUse].bufUse -= (shift);\
+}
+ edg_wll_ResetError(ctx);
+
+
+ if (ctx->connPool[ctx->connToUse].ssl) sock = SSL_get_fd(ctx->connPool[ctx->connToUse].ssl);
+ else {
+ edg_wll_SetError(ctx,ENOTCONN,NULL);
+ goto error;
+ }
+
+ if (!ctx->connPool[ctx->connToUse].buf) ctx->connPool[ctx->connToUse].buf = malloc(ctx->connPool[ctx->connToUse].bufSize = BUFSIZ);
+
+ do {
+ len = edg_wll_ssl_read(ctx->connPool[ctx->connToUse].ssl,
+ ctx->connPool[ctx->connToUse].buf+ctx->connPool[ctx->connToUse].bufUse,ctx->connPool[ctx->connToUse].bufSize-ctx->connPool[ctx->connToUse].bufUse,&ctx->p_tmp_timeout);
+
+ switch (len) {
+ case EDG_WLL_SSL_OK:
+ case EDG_WLL_SSL_ERROR_SSL:
+ edg_wll_SetError(ctx,EDG_WLL_ERROR_SSL,
+ ERR_error_string(ERR_get_error(), NULL));
+ goto error;
+ case EDG_WLL_SSL_ERROR_ERRNO:
+ edg_wll_SetError(ctx,errno,"edg_wll_ssl_read()");
+ goto error;
+ case EDG_WLL_SSL_ERROR_TIMEOUT:
+ edg_wll_SetError(ctx,ETIMEDOUT,NULL);
+ goto error;
+ case EDG_WLL_SSL_ERROR_EOF:
+ edg_wll_SetError(ctx,ENOTCONN,NULL);
+ goto error;
+ /* default: fallthrough */
+ }
+
+
+ ctx->connPool[ctx->connToUse].bufUse += len;
+ rdmore = 0;
+
+ while (!rdmore && pstat != DONE) switch (pstat) {
+ char *cr;
+
+ case FIRST:
+ if ((cr = memchr(ctx->connPool[ctx->connToUse].buf,'\r',ctx->connPool[ctx->connToUse].bufUse)) &&
+ ctx->connPool[ctx->connToUse].bufUse >= cr-ctx->connPool[ctx->connToUse].buf+2 && cr[1] == '\n')
+ {
+ *cr = 0;
+ first = strdup(ctx->connPool[ctx->connToUse].buf);
+ bshift(cr-ctx->connPool[ctx->connToUse].buf+2);
+ pstat = HEAD;
+ } else rdmore = 1;
+ break;
+ case HEAD:
+ if ((cr = memchr(ctx->connPool[ctx->connToUse].buf,'\r',ctx->connPool[ctx->connToUse].bufUse)) &&
+ ctx->connPool[ctx->connToUse].bufUse >= cr-ctx->connPool[ctx->connToUse].buf+2 && cr[1] == '\n')
+ {
+ if (cr == ctx->connPool[ctx->connToUse].buf) {
+ bshift(2);
+ pstat = clen ? BODY : DONE;
+ if (clen) body = malloc(clen+1);
+ break;
+ }
+
+ *cr = 0;
+ hdr = realloc(hdr,(nhdr+2) * sizeof(*hdr));
+ hdr[nhdr] = strdup(ctx->connPool[ctx->connToUse].buf);
+ hdr[++nhdr] = NULL;
+
+ if (!strncasecmp(ctx->connPool[ctx->connToUse].buf,CONTENT_LENGTH,sizeof(CONTENT_LENGTH)-1))
+ clen = atoi(ctx->connPool[ctx->connToUse].buf+sizeof(CONTENT_LENGTH)-1);
+
+ bshift(cr-ctx->connPool[ctx->connToUse].buf+2);
+ } else rdmore = 1;
+ break;
+ case BODY:
+ if (ctx->connPool[ctx->connToUse].bufUse) {
+ int m = min(ctx->connPool[ctx->connToUse].bufUse,clen-blen);
+ memcpy(body+blen,ctx->connPool[ctx->connToUse].buf,m);
+ blen += m;
+ bshift(m);
+ }
+ rdmore = 1;
+ if (blen == clen) {
+ pstat = DONE;
+ body[blen] = 0;
+ }
+ break;
+ default:
+ break;
+ }
+ } while (pstat != DONE);
+
+error:
+ if (edg_wll_Error(ctx,NULL,NULL)) {
+ if (hdr) {
+ char **h;
+ for (h = hdr; *h; h++) free(*h);
+ free(hdr);
+ }
+ free(first);
+ free(body);
+ } else {
+ if (firstOut) *firstOut = first; else free(first);
+ if (hdrOut) *hdrOut = hdr;
+ else if (hdr) {
+ char **h;
+ for (h = hdr; *h; h++) free(*h);
+ free(hdr);
+ }
+ if (bodyOut) *bodyOut = body; else free(body);
+ }
+
+ return edg_wll_Error(ctx,NULL,NULL);
+}
+
+static int real_write(edg_wll_Context ctx, SSL *ssl,int fd,const char *data,int len)
+{
+ int once,total = 0;
+ struct sigaction sa,osa;
+
+ memset(&sa,0,sizeof(sa)); assert(sa.sa_handler == NULL);
+ sa.sa_handler = SIG_IGN;
+ sigaction(SIGPIPE,&sa,&osa);
+
+ while (total < len) {
+ int sslerr;
+
+ switch (once = edg_wll_ssl_write(ssl,(void*)(data+total),len-total,&ctx->p_tmp_timeout)) {
+ case EDG_WLL_SSL_ERROR_EOF:
+ errno = ENOTCONN;
+ total = -1;
+ goto end;
+ case EDG_WLL_SSL_ERROR_TIMEOUT:
+ errno = ETIMEDOUT;
+ total = -1;
+ goto end;
+ case EDG_WLL_SSL_ERROR_ERRNO:
+ if (errno == EPIPE) errno = ENOTCONN;
+ total = -1;
+ goto end;
+ case EDG_WLL_SSL_OK:
+ case EDG_WLL_SSL_ERROR_SSL:
+ sslerr = SSL_get_error(ssl,once);
+ if (sslerr == SSL_ERROR_SYSCALL) {
+ if (errno == EPIPE) errno = ENOTCONN;
+ }
+ else errno = EDG_WLL_ERROR_SSL;
+ total = -1;
+ goto end;
+ default:
+ total += once;
+ }
+ }
+end:
+ sigaction(SIGPIPE,&osa,NULL);
+ return total;
+}
+
+edg_wll_ErrorCode edg_wll_http_send(edg_wll_Context ctx,const char *first,const char * const *head,const char *body)
+{
+ const char* const *h;
+ int len = 0, blen, sock;
+
+ edg_wll_ResetError(ctx);
+
+ if (ctx->connPool[ctx->connToUse].ssl) sock = SSL_get_fd(ctx->connPool[ctx->connToUse].ssl);
+ else return edg_wll_SetError(ctx,ENOTCONN,NULL);
+
+ if (real_write(ctx,ctx->connPool[ctx->connToUse].ssl,sock,first,strlen(first)) < 0 ||
+ real_write(ctx,ctx->connPool[ctx->connToUse].ssl,sock,"\r\n",2) < 0)
+ return edg_wll_SetError(ctx,errno,"edg_wll_http_send()");
+
+ if (head) for (h=head; *h; h++)
+ if (real_write(ctx,ctx->connPool[ctx->connToUse].ssl,sock,*h,strlen(*h)) < 0 ||
+ real_write(ctx,ctx->connPool[ctx->connToUse].ssl,sock,"\r\n",2) < 0)
+ return edg_wll_SetError(ctx,errno,"edg_wll_http_send()");
+
+ if (body) {
+ char buf[100];
+
+ len = strlen(body);
+ blen = sprintf(buf,CONTENT_LENGTH " %d\r\n",len);
+ if (real_write(ctx,ctx->connPool[ctx->connToUse].ssl,sock,buf,blen) < 0)
+ return edg_wll_SetError(ctx,errno,"edg_wll_http_send()");
+ }
+
+ if (real_write(ctx,ctx->connPool[ctx->connToUse].ssl,sock,"\r\n",2) < 0)
+ return edg_wll_SetError(ctx,errno,"edg_wll_http_send()");
+ if (body && real_write(ctx,ctx->connPool[ctx->connToUse].ssl,sock,body,len) < 0)
+ return edg_wll_SetError(ctx,errno,"edg_wll_http_send()");
+
+ return edg_wll_Error(ctx,NULL,NULL);
+}
--- /dev/null
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "glite/wms/jobid/cjobid.h"
+#include "notifid.h"
+
+int edg_wll_NotifIdParse(const char *s,edg_wll_NotifId *n)
+{
+ edg_wlc_JobId j;
+ int ret = edg_wlc_JobIdParse(s,&j);
+
+ if (!ret) *n = (edg_wll_NotifId) j;
+ return ret;
+}
+
+char* edg_wll_NotifIdUnparse(const edg_wll_NotifId n)
+{
+ return edg_wlc_JobIdUnparse((edg_wlc_JobId) n);
+}
+
+int edg_wll_NotifIdCreate(const char *server,int port,edg_wll_NotifId *n)
+{
+ edg_wlc_JobId j,j2;
+ int ret = edg_wlc_JobIdCreate(server,port,&j);
+ char *u,*u2;
+
+ if (!ret) {
+ u = edg_wlc_JobIdGetUnique(j);
+ asprintf(&u2,"NOTIF:%s",u);
+ free(u);
+ ret = edg_wlc_JobIdRecreate(server,port,u2,&j2);
+ free(u2);
+ edg_wlc_JobIdFree(j);
+ if (!ret) *n = (edg_wll_NotifId) j2;
+ }
+
+ return ret;
+}
+
+int edg_wll_NotifIdSetUnique(edg_wll_NotifId *n, const char *un)
+{
+ char *aux, *srv;
+ int ret;
+ unsigned int port;
+
+
+ asprintf(&aux, "NOTIF:%s", un);
+ if ( !aux )
+ return -1;
+
+ edg_wll_NotifIdGetServerParts(*((edg_wlc_JobId *)n), &srv, &port);
+ ret = edg_wlc_JobIdRecreate(srv, port, aux, (edg_wlc_JobId *)n);
+ free(aux);
+ free(srv);
+
+ return ret;
+}
+
+void edg_wll_NotifIdFree(edg_wll_NotifId n)
+{
+ edg_wlc_JobIdFree((edg_wlc_JobId) n);
+}
+
+void edg_wll_NotifIdGetServerParts(const edg_wll_NotifId notifId, char **srvName, unsigned int *srvPort)
+{
+ edg_wlc_JobIdGetServerParts((edg_wlc_JobId) notifId, srvName, srvPort);
+}
+
+char* edg_wll_NotifIdGetUnique(const edg_wll_NotifId notifid)
+{
+ char *id = edg_wlc_JobIdGetUnique((edg_wlc_JobId)notifid);
+
+ if ( id )
+ {
+ char *s = strchr(id, ':');
+
+ if ( s )
+ {
+ char *ret = strdup(s+1);
+ free(id);
+ return ret;
+ }
+ }
+
+ free(id);
+ return NULL;
+}
--- /dev/null
+#ifndef __EDG_WORKLOAD_LOGGING_COMMON_NOTIFID_H__
+#define __EDG_WORKLOAD_LOGGING_COMMON_NOTIFID_H__
+
+#ident "$Header$"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/** Notification handle.
+ * Refers to a particular registration for receiving notifications.
+ */
+typedef void *edg_wll_NotifId;
+
+/** Parse and unparse the Id. */
+int edg_wll_NotifIdParse(const char *,edg_wll_NotifId *);
+char* edg_wll_NotifIdUnparse(const edg_wll_NotifId);
+
+int edg_wll_NotifIdCreate(const char *,int,edg_wll_NotifId *);
+void edg_wll_NotifIdFree(edg_wll_NotifId);
+
+void edg_wll_NotifIdGetServerParts(const edg_wll_NotifId, char **, unsigned int *);
+char *edg_wll_NotifIdGetUnique(const edg_wll_NotifId);
+int edg_wll_NotifIdSetUnique(edg_wll_NotifId *, const char *);
+
+#ifdef __cplusplus
+}
+#endif
+#endif
--- /dev/null
+#include <string.h>
+#include <stdarg.h>
+#include <unistd.h>
+#include <sys/time.h>
+#include <errno.h>
+
+#include <globus_common.h>
+
+#include "glite/wms/jobid/cjobid.h"
+#include "glite/lb/producer.h"
+#include "glite/lb/notification.h"
+#include "context-int.h"
+#include "log_proto.h"
+
+
+/* XXX: must match edg_wll_ContextParam */
+static const char *myenv[] = {
+ "GLOBUS_HOSTNAME",
+ NULL,
+ NULL,
+ NULL,
+ "EDG_WL_LOG_DESTINATION",
+ "EDG_WL_LOG_DESTINATION",
+ "EDG_WL_LOG_TIMEOUT",
+ "EDG_WL_LOG_SYNC_TIMEOUT",
+ "EDG_WL_QUERY_SERVER",
+ "EDG_WL_QUERY_SERVER",
+ "EDG_WL_QUERY_SERVER_OVERRIDE",
+ "EDG_WL_QUERY_TIMEOUT",
+ "EDG_WL_QUERY_JOBS_LIMIT",
+ "EDG_WL_QUERY_EVENTS_LIMIT",
+ "EDG_WL_QUERY_RESULTS",
+ "EDG_WL_QUERY_CONNECTIONS",
+ "EDG_WL_NOTIF_SERVER",
+ "EDG_WL_NOTIF_SERVER",
+ "EDG_WL_NOTIF_TIMEOUT",
+/* don't care about X509_USER_*, GSI looks at them anyway */
+ NULL,
+ NULL,
+ NULL,
+};
+
+/* XXX: does not parse URL, just hostname[:port] */
+
+static int extract_port(edg_wll_ContextParam param,int dflt)
+{
+ char *p = NULL,*s = NULL;
+ if (myenv[param]) {
+ s = getenv(myenv[param]);
+ if (s) p = strchr(s,':');
+ }
+ return p ? atoi(p+1) : dflt;
+}
+
+static int extract_num(edg_wll_ContextParam param,int dflt)
+{
+ if (myenv[param]) {
+ char *s = getenv(myenv[param]);
+ if (s) return(atoi(s));
+ }
+ return dflt;
+}
+
+static char *extract_host(edg_wll_ContextParam param,const char *dflt)
+{
+ char *p,*s = NULL;
+
+ if (myenv[param]) s = getenv(myenv[param]);
+ if (!s && !dflt) return NULL;
+ s = strdup(s?s:dflt),
+ p = strchr(s,':');
+ if (p) *p = 0;
+ return s;
+}
+
+static void extract_time(edg_wll_ContextParam param,double dflt,struct timeval *t)
+{
+ char *s = NULL;
+ double d;
+
+ if (myenv[param]) s = getenv(myenv[param]);
+ d = s ? atof(s) : dflt;
+ t->tv_sec = (long) d;
+ t->tv_usec = (long) ((d-t->tv_sec)*1e6);
+}
+
+static char *extract_split(edg_wll_ContextParam param,char by,int index)
+{
+ int i;
+ char *s,*e;
+
+ if (!myenv[param]) return NULL;
+ if (!(s = getenv(myenv[param]))) return NULL;
+ for (i=0; i<index && (s=strchr(s,by));i++) s++;
+ return i==index ? ( (e = strchr(s,by)) ? strndup(s,e-s) : strdup(s))
+ : NULL;
+}
+
+
+int edg_wll_SetParamString(edg_wll_Context ctx,edg_wll_ContextParam param,const char *val)
+{
+ char hn[200];
+
+ switch (param) {
+ case EDG_WLL_PARAM_HOST:
+ globus_libc_gethostname(hn,sizeof hn);
+ free(ctx->p_host);
+ ctx->p_host = val ? strdup(val) : extract_host(param,hn);
+ break;
+ case EDG_WLL_PARAM_INSTANCE:
+ free(ctx->p_instance);
+ ctx->p_instance = val ? strdup(val) : extract_split(param,'/',1);
+ break;
+ case EDG_WLL_PARAM_DESTINATION:
+ free(ctx->p_destination);
+ ctx->p_destination = val ? strdup(val) : extract_host(param,EDG_WLL_LOG_HOST_DEFAULT);
+ break;
+ case EDG_WLL_PARAM_QUERY_SERVER:
+ free(ctx->p_query_server);
+ ctx->p_query_server = val ? strdup(val) : extract_host(param,NULL);
+ break;
+ case EDG_WLL_PARAM_NOTIF_SERVER:
+ free(ctx->p_notif_server);
+ ctx->p_notif_server = val ? strdup(val) : extract_host(param,NULL);
+ break;
+ case EDG_WLL_PARAM_X509_PROXY:
+ free(ctx->p_proxy_filename);
+ ctx->p_proxy_filename = val ? strdup(val) : NULL;
+ break;
+ case EDG_WLL_PARAM_X509_KEY:
+ free(ctx->p_key_filename);
+ ctx->p_key_filename = val ? strdup(val) : NULL;
+ break;
+ case EDG_WLL_PARAM_X509_CERT:
+ free(ctx->p_cert_filename);
+ ctx->p_cert_filename = val ? strdup(val) : NULL;
+ break;
+ case EDG_WLL_PARAM_QUERY_SERVER_OVERRIDE:
+ if (!val) val = getenv(myenv[param]);
+ if (!val) val = "no";
+ ctx->p_query_server_override = !strcasecmp(val,"yes");
+ break;
+ default:
+ return edg_wll_SetError(ctx,EINVAL,"unknown parameter");
+ }
+ return edg_wll_ResetError(ctx);
+}
+
+int edg_wll_SetParamInt(edg_wll_Context ctx,edg_wll_ContextParam param,int val)
+{
+ switch (param) {
+ case EDG_WLL_PARAM_LEVEL:
+ ctx->p_level = val ? val : EDG_WLL_LEVEL_SYSTEM;
+ break;
+ case EDG_WLL_PARAM_DESTINATION_PORT:
+ ctx->p_dest_port = val ? val : extract_port(param,EDG_WLL_LOG_PORT_DEFAULT);
+ break;
+ case EDG_WLL_PARAM_QUERY_SERVER_PORT:
+ ctx->p_query_server_port = val ? val :
+ extract_port(param,GLITE_WMSC_JOBID_DEFAULT_PORT);;
+ break;
+ case EDG_WLL_PARAM_NOTIF_SERVER_PORT:
+ ctx->p_notif_server_port = val ? val :
+ extract_port(param,0);;
+ // XXX: when default port is known, put it here
+ break;
+ case EDG_WLL_PARAM_QUERY_JOBS_LIMIT:
+ ctx->p_query_jobs_limit = val ? val :
+ extract_num(param,0);
+ break;
+ case EDG_WLL_PARAM_QUERY_EVENTS_LIMIT:
+ ctx->p_query_events_limit = val ? val :
+ extract_num(param,0);
+ break;
+ case EDG_WLL_PARAM_QUERY_RESULTS:
+ if (val) {
+ if (val <= EDG_WLL_QUERYRES_UNDEF || val >= EDG_WLL_QUERYRES__LAST)
+ return edg_wll_SetError(ctx,EINVAL,"Query result parameter value out of range");
+
+ ctx->p_query_results = val;
+ }
+ else {
+ char *s = extract_split(param,'/',0);
+ if (s) {
+ val = edg_wll_StringToQResult(s);
+ if (!val) return edg_wll_SetError(ctx,EINVAL,"can't parse query result parameter name");
+ ctx->p_query_results = val;
+ free(s);
+ }
+ return edg_wll_SetError(ctx,EINVAL,"can't parse query result parameter name");
+ }
+ break;
+ case EDG_WLL_PARAM_QUERY_CONNECTIONS:
+ {
+ char *s = getenv(myenv[param]);
+
+ if (!val && s) val = atoi(s);
+ ctx->poolSize = val ? val : EDG_WLL_LOG_CONNECTIONS_DEFAULT;
+ }
+ break;
+ case EDG_WLL_PARAM_SOURCE:
+ if (val) {
+ if (val <= EDG_WLL_SOURCE_NONE || val >= EDG_WLL_SOURCE__LAST)
+ return edg_wll_SetError(ctx,EINVAL,"Source out of range");
+
+ ctx->p_source = val;
+ }
+ else {
+ char *s = extract_split(param,'/',0);
+ if (s) {
+ val = edg_wll_StringToSource(s);
+ if (!val) return edg_wll_SetError(ctx,EINVAL,"can't parse source name");
+ ctx->p_source = val;
+ free(s);
+ }
+ return edg_wll_SetError(ctx,EINVAL,"can't parse source name");
+ }
+ break;
+ default:
+ return edg_wll_SetError(ctx,EINVAL,"unknown parameter");
+ }
+ return edg_wll_ResetError(ctx);
+}
+
+int edg_wll_SetParamTime(edg_wll_Context ctx,edg_wll_ContextParam param,const struct timeval *val)
+{
+ switch (param) {
+ case EDG_WLL_PARAM_LOG_TIMEOUT:
+/* XXX: check also if val is not grater than EDG_WLL_LOG_TIMEOUT_MAX */
+ if (val) memcpy(&ctx->p_log_timeout,val,sizeof *val);
+ else extract_time(param,EDG_WLL_LOG_TIMEOUT_DEFAULT,&ctx->p_log_timeout);
+ break;
+ case EDG_WLL_PARAM_LOG_SYNC_TIMEOUT:
+/* XXX: check also if val is not grater than EDG_WLL_LOG_SYNC_TIMEOUT_MAX */
+ if (val) memcpy(&ctx->p_sync_timeout,val,sizeof *val);
+ else extract_time(param,EDG_WLL_LOG_SYNC_TIMEOUT_DEFAULT,&ctx->p_sync_timeout);
+ break;
+ case EDG_WLL_PARAM_QUERY_TIMEOUT:
+/* XXX: check also if val is not grater than EDG_WLL_QUERY_TIMEOUT_MAX */
+ if (val) memcpy(&ctx->p_query_timeout,val,sizeof *val);
+ else extract_time(param,EDG_WLL_QUERY_TIMEOUT_DEFAULT,&ctx->p_query_timeout);
+ break;
+ case EDG_WLL_PARAM_NOTIF_TIMEOUT:
+/* XXX: check also if val is not grater than EDG_WLL_NOTIF_TIMEOUT_MAX */
+ if (val) memcpy(&ctx->p_notif_timeout,val,sizeof *val);
+ else extract_time(param,EDG_WLL_NOTIF_TIMEOUT_DEFAULT,&ctx->p_notif_timeout);
+ break;
+ default:
+ return edg_wll_SetError(ctx,EINVAL,"unknown parameter");
+ }
+ return edg_wll_ResetError(ctx);
+}
+
+int edg_wll_SetParam(edg_wll_Context ctx,edg_wll_ContextParam param,...)
+{
+ va_list ap;
+
+ va_start(ap,param);
+ switch (param) {
+ case EDG_WLL_PARAM_LEVEL:
+ case EDG_WLL_PARAM_DESTINATION_PORT:
+ case EDG_WLL_PARAM_QUERY_SERVER_PORT:
+ case EDG_WLL_PARAM_NOTIF_SERVER_PORT:
+ case EDG_WLL_PARAM_QUERY_JOBS_LIMIT:
+ case EDG_WLL_PARAM_QUERY_EVENTS_LIMIT:
+ case EDG_WLL_PARAM_QUERY_RESULTS:
+ case EDG_WLL_PARAM_QUERY_CONNECTIONS:
+ case EDG_WLL_PARAM_SOURCE:
+ return edg_wll_SetParamInt(ctx,param,va_arg(ap,int));
+ case EDG_WLL_PARAM_HOST:
+ case EDG_WLL_PARAM_INSTANCE:
+ case EDG_WLL_PARAM_DESTINATION:
+ case EDG_WLL_PARAM_QUERY_SERVER:
+ case EDG_WLL_PARAM_NOTIF_SERVER:
+ case EDG_WLL_PARAM_QUERY_SERVER_OVERRIDE:
+ case EDG_WLL_PARAM_X509_PROXY:
+ case EDG_WLL_PARAM_X509_KEY:
+ case EDG_WLL_PARAM_X509_CERT:
+ return edg_wll_SetParamString(ctx,param,va_arg(ap,char *));
+ case EDG_WLL_PARAM_LOG_TIMEOUT:
+ case EDG_WLL_PARAM_LOG_SYNC_TIMEOUT:
+ case EDG_WLL_PARAM_QUERY_TIMEOUT:
+ case EDG_WLL_PARAM_NOTIF_TIMEOUT:
+ return edg_wll_SetParamTime(ctx,param,va_arg(ap,struct timeval *));
+ default:
+ return edg_wll_SetError(ctx,EINVAL,"unknown parameter");
+ }
+}
+
+int edg_wll_GetParam(edg_wll_Context ctx,edg_wll_ContextParam param,...)
+{
+ va_list ap;
+ int *p_int;
+ char **p_string;
+ struct timeval *p_tv;
+
+ edg_wll_ResetError(ctx);
+
+ va_start(ap,param);
+ switch (param) {
+ case EDG_WLL_PARAM_LEVEL:
+ p_int = va_arg(ap, int *);
+ *p_int = ctx->p_level;
+ break;
+ case EDG_WLL_PARAM_DESTINATION_PORT:
+ p_int = va_arg(ap, int *);
+ *p_int = ctx->p_dest_port;
+ break;
+ case EDG_WLL_PARAM_QUERY_SERVER_PORT:
+ p_int = va_arg(ap, int *);
+ *p_int = ctx->p_query_server_port;
+ break;
+ case EDG_WLL_PARAM_NOTIF_SERVER_PORT:
+ p_int = va_arg(ap, int *);
+ *p_int = ctx->p_notif_server_port;
+ break;
+ case EDG_WLL_PARAM_QUERY_JOBS_LIMIT:
+ p_int = va_arg(ap, int *);
+ *p_int = ctx->p_query_jobs_limit;
+ break;
+ case EDG_WLL_PARAM_QUERY_EVENTS_LIMIT:
+ p_int = va_arg(ap, int *);
+ *p_int = ctx->p_query_events_limit;
+ break;
+ case EDG_WLL_PARAM_QUERY_RESULTS:
+ p_int = va_arg(ap, int *);
+ *p_int = ctx->p_query_results;
+ break;
+ case EDG_WLL_PARAM_QUERY_CONNECTIONS:
+ p_int = va_arg(ap, int *);
+ *p_int = ctx->poolSize;
+ break;
+ case EDG_WLL_PARAM_SOURCE:
+ p_int = va_arg(ap, int *);
+ *p_int = ctx->p_source;
+ break;
+
+#define estrdup(x) ((x) ? strdup(x) : x)
+
+ case EDG_WLL_PARAM_HOST:
+ p_string = va_arg(ap, char **);
+ *p_string = estrdup(ctx->p_host);
+ break;
+ case EDG_WLL_PARAM_INSTANCE:
+ p_string = va_arg(ap, char **);
+ *p_string = estrdup(ctx->p_instance);
+ break;
+ case EDG_WLL_PARAM_DESTINATION:
+ p_string = va_arg(ap, char **);
+ *p_string = estrdup(ctx->p_destination);
+ break;
+ case EDG_WLL_PARAM_QUERY_SERVER:
+ p_string = va_arg(ap, char **);
+ *p_string = estrdup(ctx->p_query_server);
+ break;
+ case EDG_WLL_PARAM_NOTIF_SERVER:
+ p_string = va_arg(ap, char **);
+ *p_string = estrdup(ctx->p_notif_server);
+ break;
+ case EDG_WLL_PARAM_QUERY_SERVER_OVERRIDE:
+ p_string = va_arg(ap, char **);
+ *p_string = strdup(ctx->p_query_server_override ? "yes" : "no");
+ break;
+ case EDG_WLL_PARAM_X509_PROXY:
+ p_string = va_arg(ap, char **);
+ *p_string = estrdup(ctx->p_proxy_filename);
+ break;
+ case EDG_WLL_PARAM_X509_KEY:
+ p_string = va_arg(ap, char **);
+ *p_string = estrdup(ctx->p_key_filename);
+ break;
+ case EDG_WLL_PARAM_X509_CERT:
+ p_string = va_arg(ap, char **);
+ *p_string = estrdup(ctx->p_cert_filename);
+ break;
+
+ case EDG_WLL_PARAM_LOG_TIMEOUT:
+ p_tv = va_arg(ap,struct timeval *);
+ *p_tv = ctx->p_log_timeout;
+ break;
+ case EDG_WLL_PARAM_LOG_SYNC_TIMEOUT:
+ p_tv = va_arg(ap,struct timeval *);
+ *p_tv = ctx->p_sync_timeout;
+ break;
+ case EDG_WLL_PARAM_QUERY_TIMEOUT:
+ p_tv = va_arg(ap,struct timeval *);
+ *p_tv = ctx->p_query_timeout;
+ break;
+ case EDG_WLL_PARAM_NOTIF_TIMEOUT:
+ p_tv = va_arg(ap,struct timeval *);
+ *p_tv = ctx->p_notif_timeout;
+ break;
+
+ default:
+ return edg_wll_SetError(ctx, EINVAL, "unknown parameter");
+ break;
+ }
+ va_end(ap);
+ return edg_wll_Error(ctx, NULL, NULL);
+}
+
+#if 0
+/* only for reference */
+edg_wll_ErrorCode edg_wll_SetLoggingParams(edg_wll_Context ctx,
+ const char *jobid,
+ const char *service,
+ const char *hostname,
+ const char *instance,
+ enum edg_wll_Level level,
+ const char *proxy_filename,
+ const char *cert_filename,
+ const char *key_filename)
+{
+ edg_wll_ResetError(ctx);
+
+ if (jobid != NULL) ctx->p_jobid = strdup(jobid);
+ if (service != NULL) ctx->p_service = strdup(service);
+ if (hostname != NULL) ctx->p_hostname = strdup(hostname);
+ if (instance != NULL) ctx->p_instance = strdup(instance);
+
+ ctx->p_level = level;
+
+ if (proxy_filename != NULL) ctx->p_proxy_filename = strdup(proxy_filename);
+ if (cert_filename != NULL) ctx->p_cert_filename = strdup(cert_filename);
+ if (key_filename != NULL) ctx->p_key_filename = strdup(key_filename);
+
+ return edg_wll_Error(ctx, NULL, NULL);
+}
+#endif
--- /dev/null
+#ident "$Header$"
+
+#include <string.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <stdio.h>
+#include <assert.h>
+
+#include "glite/wms/jobid/cjobid.h"
+#include "glite/lb/consumer.h"
+
+/*
+ * edg_wll_QueryRec manipulation routines
+ */
+
+void edg_wll_QueryRecFree(edg_wll_QueryRec *prec)
+{
+ if (prec == NULL) {
+ fprintf(stderr, "Error: edg_wll_QueryRecFree called with NULL parameter\n");
+ return;
+ }
+ switch (prec->attr) {
+ case EDG_WLL_QUERY_ATTR_USERTAG:
+ free(prec->attr_id.tag);
+ case EDG_WLL_QUERY_ATTR_OWNER:
+ case EDG_WLL_QUERY_ATTR_LOCATION:
+ case EDG_WLL_QUERY_ATTR_DESTINATION:
+ case EDG_WLL_QUERY_ATTR_HOST:
+ case EDG_WLL_QUERY_ATTR_INSTANCE:
+ if ( prec->value.c ) free(prec->value.c);
+ break;
+ case EDG_WLL_QUERY_ATTR_JOBID:
+ case EDG_WLL_QUERY_ATTR_PARENT:
+ edg_wlc_JobIdFree(prec->value.j);
+ break;
+ case EDG_WLL_QUERY_ATTR_STATUS:
+ case EDG_WLL_QUERY_ATTR_DONECODE:
+ case EDG_WLL_QUERY_ATTR_LEVEL:
+ case EDG_WLL_QUERY_ATTR_SOURCE:
+ case EDG_WLL_QUERY_ATTR_EVENT_TYPE:
+ case EDG_WLL_QUERY_ATTR_RESUBMITTED:
+ case EDG_WLL_QUERY_ATTR_TIME:
+ /* do nothing */
+ break;
+ default:
+ fprintf(stderr,"Error(edg_wll_QueryRecFree): unknown edg_wll_QueryRec.attr=%d\n", prec->attr);
+ break;
+ }
+}
+
--- /dev/null
+#ident "$Header$"
+
+#include <stdlib.h>
+#include <string.h>
+
+#include "glite/lb/consumer.h"
+
+static const struct timeval null_timeval = {0,0};
+
+
+void edg_wll_FreeStatus(edg_wll_JobStat *stat)
+{
+ if (stat) {
+ int i;
+
+@@@{
+ selectType $status '_common_';
+ for (getFieldsOrdered $status) {
+ my $f = selectField $status $_;
+ my $ft = $f->{type};
+ if ($ft eq 'jobid') {
+ gen "\tedg_wlc_JobIdFree(stat->$_);\n";
+ }
+ if ($ft eq 'string') {
+ gen "\tif (stat->$_ != NULL ) \tfree(stat->$_);\n";
+ }
+ if ($ft eq 'intlist') {
+ gen "\tif (stat->$_ != NULL ) \tfree(stat->$_);\n";
+ }
+ if ($ft eq 'strlist') {
+ gen "\tif (stat->$_ != NULL ) {\n";
+ gen "\t\tfor (i=0; stat->$_\[i]; i++)\n";
+ gen "\t\t\tfree(stat->$_\[i]);\n";
+ gen "\t\tfree(stat->$_);\n";
+ gen "\t}\n";
+ }
+ if ($ft eq 'taglist') {
+ gen "\tif (stat->$_ != NULL ) {\n";
+ gen "\t\tfor (i=0; stat->$_\[i].tag; i++) {\n";
+ gen "\t\t\tfree(stat->$_\[i].tag);\n";
+ gen "\t\t\tfree(stat->$_\[i].value);\n";
+ gen "\t\t}\n";
+ gen "\t\tfree(stat->$_);\n";
+ gen "\t}\n";
+ }
+ if ($ft eq 'stslist') {
+ gen "\tif (stat->$_ != NULL ) {\n";
+ gen "\t\tfor (i=0; stat->$_\[i].state; i++)\n";
+ gen "\t\t\tedg_wll_FreeStatus(&stat->$_\[i]);\n";
+ gen "\t\tfree(stat->$_);\n";
+ gen "\t}\n";
+ }
+
+ }
+@@@}
+
+ }
+}
+
+edg_wll_JobStat *edg_wll_CpyStatus(const edg_wll_JobStat *src, edg_wll_JobStat *dest)
+{
+ int i;
+
+
+ if ( !src || !dest )
+ return NULL;
+
+ edg_wll_InitStatus(dest);
+ dest->state = src->state;
+@@@{
+ selectType $status '_common_';
+ for (getFieldsOrdered $status) {
+ my $f = selectField $status $_;
+ my $ft = $f->{type};
+ if ($ft eq 'jobid') {
+ gen "\tif ( edg_wlc_JobIdDup(src->$_, &(dest->$_)) ) goto err;\n";
+ }
+ if ($ft eq 'string') {
+ gen "\tif ( src->$_ != NULL )\n";
+ gen "\t\tif ( !(dest->$_ = strdup(src->$_)) ) goto err;\n";
+ }
+ if ($ft eq 'intlist') {
+ gen "\tif ( src->$_ != NULL )\n\t{\n";
+ gen "\t\ti = 1 + src->$_\[0];\n";
+ gen "\t\tif ( !(dest->$_ = malloc(sizeof(*src->$_)*i)) ) goto err;\n";
+ gen "\t\tmemcpy(dest->$_,src->$_,sizeof(*src->$_)*i);\n\t}\n";
+ }
+ if ($ft eq 'strlist') {
+ gen "\tif ( src->$_ != NULL )\n\t{\n";
+ gen "\t\tfor ( i = 0; src->$_\[i]; i++ ) ;\n";
+ gen "\t\tif ( !(dest->$_ = malloc(sizeof(*src->$_)*(i+1))) ) goto err;\n";
+ gen "\t\tfor ( i = 0; src->$_\[i]; i++ )\n";
+ gen "\t\t\tif ( !(dest->$_\[i] = strdup(src->$_\[i])) ) goto err;\n";
+ gen "\t\tdest->$_\[i] = NULL;\n\t}\n";
+ }
+ if ($ft eq 'stslist') {
+ gen "\tif ( src->$_ != NULL )\n\t{\n";
+ gen "\t\tfor ( i = 0; src->$_\[i].state; i++ ) ;\n";
+ gen "\t\tif ( !(dest->$_ = malloc(sizeof(*src->$_)*(i+1))) ) goto err;\n";
+ gen "\t\tfor ( i = 0; src->$_\[i].state; i++ )\n";
+ gen "\t\t\tif ( !edg_wll_CpyStatus(&src->$_\[i], &dest->$_\[i]) ) goto err;\n";
+ gen "\t\tdest->$_\[i].state = EDG_WLL_JOB_UNDEF;\n\t}\n";
+ }
+ if (($ft eq 'bool') or ($ft eq 'timeval') or ($ft eq 'logsrc')
+ or ($ft eq 'port') or ($ft eq 'level') or ($ft eq 'int')) {
+ gen "\tdest->$_ = src->$_;\n";
+ }
+ if ($ft eq 'taglist') {
+ gen qq{
+! if (src->$_ != NULL) \{
+! for (i=0; src->$_\[i].tag; i++);
+! dest->$_ = malloc(sizeof(*src->$_)*(i+1));
+! for (i=0; src->$_\[i].tag; i++) \{
+! dest->$_\[i].tag = strdup(src->$_\[i].tag);
+! dest->$_\[i].value = strdup(src->$_\[i].value);
+! \}
+! dest->$_\[i].tag = NULL;
+! \}
+ };
+ }
+ }
+@@@}
+
+ return dest;
+
+err:
+ edg_wll_FreeStatus(dest);
+ return NULL;
+}
+
+
+int edg_wll_InitStatus(edg_wll_JobStat *stat)
+{
+ if (!stat) return -1;
+
+ stat->state = EDG_WLL_JOB_UNDEF;
+
+@@@{
+ selectType $status '_common_';
+ for (getFieldsOrdered $status) {
+ my $f = selectField $status $_;
+ gen "\tstat->$_ = $f->{null};\n"
+ }
+@@@}
+
+ return 0;
+}
+
+static const char * const statNames[] = {
+ "Undefined",
+@@@{
+ for (getTypesOrdered $status) {
+ gen "\t\"$_\",\n";
+ }
+@@@}
+};
+
+edg_wll_JobStatCode edg_wll_StringToStat(const char *name)
+
+{
+ unsigned int i;
+
+ for (i=0; i<sizeof(statNames)/sizeof(statNames[0]); i++)
+ if (strcasecmp(statNames[i],name) == 0) return (edg_wll_JobStatCode) i;
+ return (edg_wll_JobStatCode) -1;
+}
+
+char *edg_wll_StatToString(edg_wll_JobStatCode statCode)
+{
+ if ((int)statCode < 0 || statCode >= sizeof(statNames)/sizeof(statNames[0])) return (char *) NULL;
+ return strdup(statNames[statCode]);
+}
--- /dev/null
+/*************************************************************************
+ *
+ * $Id$
+ *
+ * Copyright (C) 1998 Bjorn Reese and Daniel Stenberg.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
+ * MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE AUTHORS AND
+ * CONTRIBUTORS ACCEPT NO RESPONSIBILITY IN ANY CONCEIVABLE MANNER.
+ *
+ ************************************************************************/
+
+/*
+ * TODO
+ * - StrToLongDouble
+ */
+
+static const char rcsid[] = "@(#)$Id$";
+
+#if defined(unix) || defined(__xlC__) || defined(__QNX__)
+# define PLATFORM_UNIX
+#elif defined(WIN32) || defined(_WIN32)
+# define PLATFORM_WIN32
+#elif defined(AMIGA) && defined(__GNUC__)
+# define PLATFORM_UNIX
+#endif
+
+#if defined(__STDC__) && (__STDC_VERSION__ >= 199901L)
+# define TRIO_C99
+#endif
+
+#include "strio.h"
+#include <string.h>
+#include <locale.h>
+#include <ctype.h>
+#include <stdarg.h>
+#include <time.h>
+#include <math.h>
+#ifndef DEBUG
+# define NDEBUG
+#endif
+#include <assert.h>
+
+#ifndef NULL
+# define NULL 0
+#endif
+#define NIL ((char)0)
+#ifndef FALSE
+# define FALSE (1 == 0)
+# define TRUE (! FALSE)
+#endif
+
+#define VALID(x) (NULL != (x))
+#define INVALID(x) (NULL == (x))
+
+#if defined(PLATFORM_UNIX)
+# define USE_STRCASECMP
+# define USE_STRNCASECMP
+# define USE_STRERROR
+# if defined(__QNX__)
+# define strcasecmp(x,y) stricmp(x,y)
+# define strncasecmp(x,y,n) strnicmp(x,y,n)
+# endif
+#elif defined(PLATFORM_WIN32)
+# define USE_STRCASECMP
+# define strcasecmp(x,y) strcmpi(x,y)
+#endif
+
+/*************************************************************************
+ * StrAppendMax
+ */
+char *StrAppendMax(char *target, size_t max, const char *source)
+{
+ assert(VALID(target));
+ assert(VALID(source));
+ assert(max > 0);
+
+ max -= StrLength(target) + 1;
+ return (max > 0) ? strncat(target, source, max) : target;
+}
+
+/*************************************************************************
+ * StrCopyMax
+ */
+char *StrCopyMax(char *target, size_t max, const char *source)
+{
+ assert(VALID(target));
+ assert(VALID(source));
+ assert(max > 0); /* Includes != 0 */
+
+ target = strncpy(target, source, max - 1);
+ target[max - 1] = (char)0;
+ return target;
+}
+
+/*************************************************************************
+ * StrDuplicate
+ */
+char *StrDuplicate(const char *source)
+{
+ char *target;
+
+ assert(VALID(source));
+
+ target = StrAlloc(StrLength(source) + 1);
+ if (target)
+ {
+ StrCopy(target, source);
+ }
+ return target;
+}
+
+/*************************************************************************
+ * StrDuplicateMax
+ */
+char *StrDuplicateMax(const char *source, size_t max)
+{
+ char *target;
+ size_t len;
+
+ assert(VALID(source));
+ assert(max > 0);
+
+ /* Make room for string plus a terminating zero */
+ len = StrLength(source) + 1;
+ if (len > max)
+ {
+ len = max;
+ }
+ target = StrAlloc(len);
+ if (target)
+ {
+ StrCopyMax(target, len, source);
+ }
+ return target;
+}
+
+/*************************************************************************
+ * StrEqual
+ */
+int StrEqual(const char *first, const char *second)
+{
+ assert(VALID(first));
+ assert(VALID(second));
+
+ if (VALID(first) && VALID(second))
+ {
+#if defined(USE_STRCASECMP)
+ return (0 == strcasecmp(first, second));
+#else
+ while ((*first != NIL) && (*second != NIL))
+ {
+ if (toupper(*first) != toupper(*second))
+ {
+ break;
+ }
+ first++;
+ second++;
+ }
+ return ((*first == NIL) && (*second == NIL));
+#endif
+ }
+ return FALSE;
+}
+
+/*************************************************************************
+ * StrEqualCase
+ */
+int StrEqualCase(const char *first, const char *second)
+{
+ assert(VALID(first));
+ assert(VALID(second));
+
+ if (VALID(first) && VALID(second))
+ {
+ return (0 == strcmp(first, second));
+ }
+ return FALSE;
+}
+
+/*************************************************************************
+ * StrEqualCaseMax
+ */
+int StrEqualCaseMax(const char *first, size_t max, const char *second)
+{
+ assert(VALID(first));
+ assert(VALID(second));
+
+ if (VALID(first) && VALID(second))
+ {
+ return (0 == strncmp(first, second, max));
+ }
+ return FALSE;
+}
+
+/*************************************************************************
+ * StrEqualLocale
+ */
+int StrEqualLocale(const char *first, const char *second)
+{
+ assert(VALID(first));
+ assert(VALID(second));
+
+#if defined(LC_COLLATE)
+ return (strcoll(first, second) == 0);
+#else
+ return StrEqual(first, second);
+#endif
+}
+
+/*************************************************************************
+ * StrEqualMax
+ */
+int StrEqualMax(const char *first, size_t max, const char *second)
+{
+ assert(VALID(first));
+ assert(VALID(second));
+
+ if (VALID(first) && VALID(second))
+ {
+#if defined(USE_STRNCASECMP)
+ return (0 == strncasecmp(first, second, max));
+#else
+ /* Not adequately tested yet */
+ size_t cnt = 0;
+ while ((*first != NIL) && (*second != NIL) && (cnt <= max))
+ {
+ if (toupper(*first) != toupper(*second))
+ {
+ break;
+ }
+ first++;
+ second++;
+ cnt++;
+ }
+ return ((cnt == max) || ((*first == NIL) && (*second == NIL)));
+#endif
+ }
+ return FALSE;
+}
+
+/*************************************************************************
+ * StrError
+ */
+const char *StrError(int errorNumber)
+{
+#if defined(USE_STRERROR)
+ return strerror(errorNumber);
+#else
+ return "unknown";
+#endif
+}
+
+/*************************************************************************
+ * StrFormatDate
+ */
+size_t StrFormatDateMax(char *target,
+ size_t max,
+ const char *format,
+ const struct tm *datetime)
+{
+ assert(VALID(target));
+ assert(VALID(format));
+ assert(VALID(datetime));
+ assert(max > 0);
+
+ return strftime(target, max, format, datetime);
+}
+
+/*************************************************************************
+ * StrHash
+ */
+unsigned long StrHash(const char *string, int type)
+{
+ unsigned long value = 0L;
+ char ch;
+
+ assert(VALID(string));
+
+ switch (type)
+ {
+ case STRIO_HASH_PLAIN:
+ while ( (ch = *string++) != NIL )
+ {
+ value *= 31;
+ value += (unsigned long)ch;
+ }
+ break;
+ default:
+ assert(FALSE);
+ break;
+ }
+ return value;
+}
+
+/*************************************************************************
+ * StrMatch
+ */
+int StrMatch(char *string, char *pattern)
+{
+ assert(VALID(string));
+ assert(VALID(pattern));
+
+ for (; ('*' != *pattern); ++pattern, ++string)
+ {
+ if (NIL == *string)
+ {
+ return (NIL == *pattern);
+ }
+ if ((toupper((int)*string) != toupper((int)*pattern))
+ && ('?' != *pattern))
+ {
+ return FALSE;
+ }
+ }
+ /* two-line patch to prevent *too* much recursiveness: */
+ while ('*' == pattern[1])
+ pattern++;
+
+ do
+ {
+ if ( StrMatch(string, &pattern[1]) )
+ {
+ return TRUE;
+ }
+ }
+ while (*string++);
+
+ return FALSE;
+}
+
+/*************************************************************************
+ * StrMatchCase
+ */
+int StrMatchCase(char *string, char *pattern)
+{
+ assert(VALID(string));
+ assert(VALID(pattern));
+
+ for (; ('*' != *pattern); ++pattern, ++string)
+ {
+ if (NIL == *string)
+ {
+ return (NIL == *pattern);
+ }
+ if ((*string != *pattern)
+ && ('?' != *pattern))
+ {
+ return FALSE;
+ }
+ }
+ /* two-line patch to prevent *too* much recursiveness: */
+ while ('*' == pattern[1])
+ pattern++;
+
+ do
+ {
+ if ( StrMatchCase(string, &pattern[1]) )
+ {
+ return TRUE;
+ }
+ }
+ while (*string++);
+
+ return FALSE;
+}
+
+/*************************************************************************
+ * StrSpanFunction
+ *
+ * Untested
+ */
+size_t StrSpanFunction(char *source, int (*Function)(int))
+{
+ size_t count = 0;
+
+ assert(VALID(source));
+ assert(VALID(Function));
+
+ while (*source != NIL)
+ {
+ if (Function(*source))
+ break; /* while */
+ source++;
+ count++;
+ }
+ return count;
+}
+
+/*************************************************************************
+ * StrSubstringMax
+ */
+char *StrSubstringMax(const char *string, size_t max, const char *find)
+{
+ size_t count;
+ size_t size;
+ char *result = NULL;
+
+ assert(VALID(string));
+ assert(VALID(find));
+
+ size = StrLength(find);
+ if (size <= max)
+ {
+ for (count = 0; count <= max - size; count++)
+ {
+ if (StrEqualMax(find, size, &string[count]))
+ {
+ result = (char *)&string[count];
+ break;
+ }
+ }
+ }
+ return result;
+}
+
+/*************************************************************************
+ * StrToDouble
+ *
+ * double ::= [ <sign> ]
+ * ( <number> |
+ * <number> <decimal_point> <number> |
+ * <decimal_point> <number> )
+ * [ <exponential> [ <sign> ] <number> ]
+ * number ::= 1*( <digit> )
+ * digit ::= ( '0' | '1' | '2' | '3' | '4' | '5' | '6' | '7' | '8' | '9' )
+ * exponential ::= ( 'e' | 'E' )
+ * sign ::= ( '-' | '+' )
+ * decimal_point ::= '.'
+ */
+double StrToDouble(const char *source, const char **endp)
+{
+#if defined(TRIO_C99)
+ return strtod(source, endp);
+#else
+ /* Preliminary code */
+ int isNegative = FALSE;
+ int isExponentNegative = FALSE;
+ unsigned long integer = 0;
+ unsigned long fraction = 0;
+ unsigned long fracdiv = 1;
+ unsigned long exponent = 0;
+ double value = 0.0;
+
+ /* First try hex-floats */
+ if ((source[0] == '0') && ((source[1] == 'x') || (source[1] == 'X')))
+ {
+ source += 2;
+ while (isxdigit((int)*source))
+ {
+ integer *= 16;
+ integer += (isdigit((int)*source)
+ ? (*source - '0')
+ : 10 + (toupper((int)*source) - 'A'));
+ source++;
+ }
+ if (*source == '.')
+ {
+ source++;
+ while (isxdigit((int)*source))
+ {
+ fraction *= 16;
+ fraction += (isdigit((int)*source)
+ ? (*source - '0')
+ : 10 + (toupper((int)*source) - 'A'));
+ fracdiv *= 16;
+ source++;
+ }
+ if ((*source == 'p') || (*source == 'P'))
+ {
+ source++;
+ if ((*source == '+') || (*source == '-'))
+ {
+ isExponentNegative = (*source == '-');
+ source++;
+ }
+ while (isdigit((int)*source))
+ {
+ exponent *= 10;
+ exponent += (*source - '0');
+ source++;
+ }
+ }
+ }
+ }
+ else /* Then try normal decimal floats */
+ {
+ isNegative = (*source == '-');
+ /* Skip sign */
+ if ((*source == '+') || (*source == '-'))
+ source++;
+
+ /* Integer part */
+ while (isdigit((int)*source))
+ {
+ integer *= 10;
+ integer += (*source - '0');
+ source++;
+ }
+
+ if (*source == '.')
+ {
+ source++; /* skip decimal point */
+ while (isdigit((int)*source))
+ {
+ fraction *= 10;
+ fraction += (*source - '0');
+ fracdiv *= 10;
+ source++;
+ }
+ }
+ if ((*source == 'e') || (*source == 'E'))
+ {
+ source++; /* Skip exponential indicator */
+ isExponentNegative = (*source == '-');
+ if ((*source == '+') || (*source == '-'))
+ source++;
+ while (isdigit((int)*source))
+ {
+ exponent *= 10;
+ exponent += (*source - '0');
+ source++;
+ }
+ }
+ }
+
+ value = (double)integer;
+ if (fraction != 0)
+ {
+ value += (double)fraction / (double)fracdiv;
+ }
+ if (exponent != 0)
+ {
+ if (isExponentNegative)
+ value /= pow((double)10, (double)exponent);
+ else
+ value *= pow((double)10, (double)exponent);
+ }
+ if (isNegative)
+ value = -value;
+
+ if (endp)
+ *endp = source;
+ return value;
+#endif
+}
+
+/*************************************************************************
+ * StrToFloat
+ */
+float StrToFloat(const char *source, const char **endp)
+{
+#if defined(TRIO_C99)
+ return strtof(source, endp);
+#else
+ return (float)StrToDouble(source, endp);
+#endif
+}
+
+/*************************************************************************
+ * StrToUpper
+ */
+int StrToUpper(char *target)
+{
+ int i = 0;
+
+ assert(VALID(target));
+
+ while (NIL != *target)
+ {
+ *target = toupper((int)*target);
+ target++;
+ i++;
+ }
+ return i;
+}
--- /dev/null
+/*************************************************************************
+ *
+ * $Id$
+ *
+ * Copyright (C) 1998 Bjorn Reese and Daniel Stenberg.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
+ * MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE AUTHORS AND
+ * CONTRIBUTORS ACCEPT NO RESPONSIBILITY IN ANY CONCEIVABLE MANNER.
+ *
+ ************************************************************************/
+
+#ifndef TRIO_STRIO_H
+#define TRIO_STRIO_H
+
+#if !(defined(DEBUG) || defined(NDEBUG))
+# define NDEBUG
+#endif
+#include <assert.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+
+#ifndef STRIO_MALLOC
+# define STRIO_MALLOC(n) malloc(n)
+#endif
+#ifndef STRIO_FREE
+# define STRIO_FREE(x) free(x)
+#endif
+
+/*
+ * StrAppend(target, source)
+ * StrAppendMax(target, maxsize, source)
+ *
+ * Append 'source' to 'target'
+ *
+ * target = StrAlloc(size)
+ *
+ * Allocate a new string
+ *
+ * StrContains(target, substring)
+ *
+ * Find out if the string 'substring' is
+ * contained in the string 'target'
+ *
+ * StrCopy(target, source)
+ * StrCopyMax(target, maxsize, source)
+ *
+ * Copy 'source' to 'target'
+ *
+ * target = StrDuplicate(source)
+ * target = StrDuplicateMax(source, maxsize)
+ *
+ * Allocate and copy 'source' to 'target'
+ *
+ * StrEqual(first, second)
+ * StrEqualMax(first, maxsize, second)
+ *
+ * Compare if 'first' is equal to 'second'.
+ * Case-independent.
+ *
+ * StrEqualCase(first, second)
+ * StrEqualCaseMax(first, maxsize, second)
+ *
+ * Compare if 'first' is equal to 'second'
+ * Case-dependent. Please note that the use of the
+ * word 'case' has the opposite meaning as that of
+ * strcasecmp().
+ *
+ * StrFormat(target, format, ...)
+ * StrFormatMax(target, maxsize, format, ...)
+ *
+ * Build 'target' according to 'format' and succesive
+ * arguments. This is equal to the sprintf() and
+ * snprintf() functions.
+ *
+ * StrFormatDate(target, format, ...)
+ *
+ * StrFree(target)
+ *
+ * De-allocates a string
+ *
+ * StrHash(string, type)
+ *
+ * Calculates the hash value of 'string' based on the
+ * 'type'.
+ *
+ * StrIndex(target, character)
+ * StrIndexLast(target, character)
+ *
+ * Find the first/last occurrence of 'character' in
+ * 'target'
+ *
+ * StrLength(target)
+ *
+ * Return the length of 'target'
+ *
+ * StrMatch(string, pattern)
+ * StrMatchCase(string, pattern)
+ *
+ * Find 'pattern' within 'string'. 'pattern' may contain
+ * wildcards such as * (asterics) and ? (question mark)
+ * which matches zero or more characters and exactly
+ * on character respectively
+ *
+ * StrScan(source, format, ...)
+ *
+ * Equal to sscanf()
+ *
+ * StrSubstring(target, substring)
+ *
+ * Find the first occurrence of the string 'substring'
+ * within the string 'target'
+ *
+ * StrTokenize(target, list)
+ *
+ * Split 'target' into the first token delimited by
+ * one of the characters in 'list'. If 'target' is
+ * NULL then next token will be returned.
+ *
+ * StrToUpper(target)
+ *
+ * Convert all lower case characters in 'target' into
+ * upper case characters.
+ */
+
+enum {
+ STRIO_HASH_NONE = 0,
+ STRIO_HASH_PLAIN,
+ STRIO_HASH_TWOSIGNED
+};
+
+#if !defined(DEBUG) || defined(__DECC)
+#define StrAlloc(n) (char *)STRIO_MALLOC(n)
+#define StrAppend(x,y) strcat((x), (y))
+#define StrContains(x,y) (0 != strstr((x), (y)))
+#define StrCopy(x,y) strcpy((x), (y))
+#define StrIndex(x,y) strchr((x), (y))
+#define StrIndexLast(x,y) strrchr((x), (y))
+#define StrFree(x) STRIO_FREE(x)
+#define StrLength(x) strlen((x))
+#define StrSubstring(x,y) strstr((x), (y))
+#define StrTokenize(x,y) strtok((x), (y))
+#define StrToLong(x,y,n) strtol((x), (y), (n))
+#define StrToUnsignedLong(x,y,n) strtoul((x), (y), (n))
+#else /* DEBUG */
+ /*
+ * To be able to use these macros everywhere, including in
+ * if() sentences, the assertions are put first in a comma
+ * seperated list.
+ *
+ * Unfortunately the DECC compiler does not seem to like this
+ * so it will use the un-asserted functions above for the
+ * debugging case too.
+ */
+#define StrAlloc(n) \
+ (assert((n) > 0),\
+ (char *)STRIO_MALLOC(n))
+#define StrAppend(x,y) \
+ (assert((x) != NULL),\
+ assert((y) != NULL),\
+ strcat((x), (y)))
+#define StrContains(x,y) \
+ (assert((x) != NULL),\
+ assert((y) != NULL),\
+ (0 != strstr((x), (y))))
+#define StrCopy(x,y) \
+ (assert((x) != NULL),\
+ assert((y) != NULL),\
+ strcpy((x), (y)))
+#define StrIndex(x,c) \
+ (assert((x) != NULL),\
+ strchr((x), (c)))
+#define StrIndexLast(x,c) \
+ (assert((x) != NULL),\
+ strrchr((x), (c)))
+#define StrFree(x) \
+ (assert((x) != NULL),\
+ STRIO_FREE(x))
+#define StrLength(x) \
+ (assert((x) != NULL),\
+ strlen((x)))
+#define StrSubstring(x,y) \
+ (assert((x) != NULL),\
+ assert((y) != NULL),\
+ strstr((x), (y)))
+#define StrTokenize(x,y) \
+ (assert((y) != NULL),\
+ strtok((x), (y)))
+#define StrToLong(x,y,n) \
+ (assert((x) != NULL),\
+ assert((y) != NULL),\
+ assert((n) >= 2 && (n) <= 36),\
+ strtol((x), (y), (n)))
+#define StrToUnsignedLong(x,y,n) \
+ (assert((x) != NULL),\
+ assert((y) != NULL),\
+ assert((n) >= 2 && (n) <= 36),\
+ strtoul((x), (y), (n)))
+#endif /* DEBUG */
+
+char *StrAppendMax(char *target, size_t max, const char *source);
+char *StrCopyMax(char *target, size_t max, const char *source);
+char *StrDuplicate(const char *source);
+char *StrDuplicateMax(const char *source, size_t max);
+int StrEqual(const char *first, const char *second);
+int StrEqualCase(const char *first, const char *second);
+int StrEqualCaseMax(const char *first, size_t max, const char *second);
+int StrEqualLocale(const char *first, const char *second);
+int StrEqualMax(const char *first, size_t max, const char *second);
+const char *StrError(int);
+size_t StrFormatDateMax(char *target, size_t max, const char *format, const struct tm *datetime);
+unsigned long StrHash(const char *string, int type);
+int StrMatch(char *string, char *pattern);
+int StrMatchCase(char *string, char *pattern);
+size_t StrSpanFunction(char *source, int (*Function)(int));
+char *StrSubstringMax(const char *string, size_t max, const char *find);
+float StrToFloat(const char *source, const char **target);
+double StrToDouble(const char *source, const char **target);
+int StrToUpper(char *target);
+
+#endif /* TRIO_STRIO_H */
--- /dev/null
+
+/*************************************************************************
+ *
+ * $Id$
+ *
+ * Copyright (C) 1998 Bjorn Reese and Daniel Stenberg.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
+ * MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE AUTHORS AND
+ * CONTRIBUTORS ACCEPT NO RESPONSIBILITY IN ANY CONCEIVABLE MANNER.
+ *
+ *************************************************************************
+ *
+ * A note to trio contributors:
+ *
+ * Avoid heap allocation at all costs to ensure that the trio functions
+ * are async-safe. The exceptions are the printf/fprintf functions, which
+ * uses fputc, and the asprintf functions and the <alloc> modifier, which
+ * by design are required to allocate form the heap.
+ *
+ ************************************************************************/
+
+/*
+ * TODO:
+ * - Scan is probably too permissive about its modifiers.
+ * - C escapes in %#[] ?
+ * - C99 support has not been properly tested.
+ * - Multibyte characters (done for format parsing, except scan groups)
+ * - Complex numbers? (C99 _Complex)
+ * - Boolean values? (C99 _Bool)
+ * - C99 NaN(n-char-sequence) missing
+ * - Should we support the GNU %a alloc modifier? GNU has an ugly hack
+ * for %a, because C99 used %a for other purposes. If specified as
+ * %as or %a[ it is interpreted as the alloc modifier, otherwise as
+ * the C99 hex-float. This means that you cannot scan %as as a hex-float
+ * immediately followed by an 's'.
+ * - Scanning of collating symbols.
+ */
+
+static const char rcsid[] = "@(#)$Id$";
+
+/*************************************************************************
+ * Trio include files
+ */
+#include "trio.h"
+#include "triop.h"
+#include "strio.h"
+
+#ifdef DATAGRID_EXTENSION
+#include "glite/lb/events.h"
+#include "escape.h"
+//#include "edg/workload/thirdparty/trio/events.h"
+#endif
+
+/*
+ * Encode the error code and the position. This is decoded
+ * with TRIO_ERROR_CODE and TRIO_ERROR_POSITION.
+ */
+#if TRIO_ERRORS
+# define TRIO_ERROR_RETURN(x,y) (- ((x) + ((y) << 8)))
+#else
+# define TRIO_ERROR_RETURN(x,y) (-1)
+#endif
+
+
+/*************************************************************************
+ * Platform and compiler support detection
+ */
+#if defined(unix) || defined(__xlC__) || defined(_AIX) || defined(__QNX__)
+# define PLATFORM_UNIX
+#elif defined(AMIGA) && defined(__GNUC__)
+# define PLATFORM_UNIX
+#elif defined(WIN32) || defined(_WIN32) || defined(_MSC_VER)
+# define PLATFORM_WIN32
+# define TRIO_MSVC_5 1100
+#endif
+
+#if defined(__STDC__) && defined(__STDC_VERSION__)
+# if (__STDC_VERSION__ >= 199409L)
+# define TRIO_COMPILER_SUPPORTS_ISO94
+# endif
+# if (__STDC_VERSION__ >= 199901L)
+# define TRIO_COMPILER_SUPPORTS_C99
+# endif
+#endif
+
+#if defined(_XOPEN_SOURCE) && defined(_XOPEN_SOURCE_EXTENDED)
+# define TRIO_COMPILER_SUPPORTS_UNIX98
+#endif
+
+#if defined(__STDC_ISO_10646__) || defined(MB_LEN_MAX) || defined(USE_MULTIBYTE) || TRIO_WIDECHAR
+# define TRIO_COMPILER_SUPPORTS_MULTIBYTE
+# if !defined(MB_LEN_MAX)
+# define MB_LEN_MAX 6
+# endif
+#endif
+
+
+/*************************************************************************
+ * Generic definitions
+ */
+
+#if !(defined(DEBUG) || defined(NDEBUG))
+# define NDEBUG
+#endif
+#include <assert.h>
+#include <ctype.h>
+#if !defined(TRIO_COMPILER_SUPPORTS_C99) && !defined(isblank)
+# define isblank(x) (((x)==32) || ((x)==9))
+#endif
+#include <math.h>
+#include <limits.h>
+#include <float.h>
+#include <stdarg.h>
+#include <stddef.h>
+#include <errno.h>
+
+#ifndef NULL
+# define NULL 0
+#endif
+#define NIL ((char)0)
+#ifndef FALSE
+# define FALSE (1 == 0)
+# define TRUE (! FALSE)
+#endif
+#define BOOLEAN_T int
+
+/* mincore() can be used for debugging purposes */
+#define VALID(x) (NULL != (x))
+
+/* xlC crashes on log10(0) */
+#define guarded_log10(x) (((x) == 0.0) ? -HUGE_VAL : log10(x))
+#define guarded_log16(x) (guarded_log10(x) / log10(16.0))
+
+
+/*************************************************************************
+ * Platform specific definitions
+ */
+#if defined(PLATFORM_UNIX)
+# include <unistd.h>
+# include <signal.h>
+# include <locale.h>
+# define USE_LOCALE
+#endif /* PLATFORM_UNIX */
+#if defined(PLATFORM_WIN32)
+# include <io.h>
+# define read _read
+# define write _write
+#endif /* PLATFORM_WIN32 */
+
+#if TRIO_WIDECHAR
+# if defined(TRIO_COMPILER_SUPPORTS_ISO94)
+# include <wchar.h>
+# include <wctype.h>
+# else
+typedef char wchar_t;
+typedef int wint_t;
+# define WEOF EOF
+# define iswalnum(x) isalnum(x)
+# define iswalpha(x) isalpha(x)
+# define iswblank(x) isblank(x)
+# define iswcntrl(x) iscntrl(x)
+# define iswdigit(x) isdigit(x)
+# define iswgraph(x) isgraph(x)
+# define iswlower(x) islower(x)
+# define iswprint(x) isprint(x)
+# define iswpunct(x) ispunct(x)
+# define iswspace(x) isspace(x)
+# define iswupper(x) isupper(x)
+# define iswxdigit(x) isxdigit(x)
+# endif
+#endif
+
+
+/*************************************************************************
+ * Compiler dependent definitions
+ */
+
+/* Support for long long */
+#ifndef __cplusplus
+# if !defined(USE_LONGLONG)
+# if defined(__GNUC__) && !defined(__STRICT_ANSI__)
+# define USE_LONGLONG
+# elif defined(__SUNPRO_C)
+# define USE_LONGLONG
+# elif defined(_LONG_LONG) || defined(_LONGLONG)
+# define USE_LONGLONG
+# endif
+# endif
+#endif
+
+/* The extra long numbers */
+#if defined(USE_LONGLONG)
+typedef signed long long int trio_longlong_t;
+typedef unsigned long long int trio_ulonglong_t;
+#elif defined(_MSC_VER)
+# if (_MSC_VER >= TRIO_MSVC_5)
+typedef signed __int64 trio_longlong_t;
+typedef unsigned __int64 trio_ulonglong_t;
+# else
+typedef signed long int trio_longlong_t;
+typedef unsigned long int trio_ulonglong_t;
+# endif
+#else
+typedef signed long int trio_longlong_t;
+typedef unsigned long int trio_ulonglong_t;
+#endif
+
+/* Maximal and fixed integer types */
+#if defined(TRIO_COMPILER_SUPPORTS_C99)
+# include <stdint.h>
+typedef intmax_t trio_intmax_t;
+typedef uintmax_t trio_uintmax_t;
+typedef int8_t trio_int8_t;
+typedef int16_t trio_int16_t;
+typedef int32_t trio_int32_t;
+typedef int64_t trio_int64_t;
+#elif defined(TRIO_COMPILER_SUPPORTS_UNIX98)
+# include <inttypes.h>
+typedef intmax_t trio_intmax_t;
+typedef uintmax_t trio_uintmax_t;
+typedef int8_t trio_int8_t;
+typedef int16_t trio_int16_t;
+typedef int32_t trio_int32_t;
+typedef int64_t trio_int64_t;
+#elif defined(_MSC_VER) && (_MSC_VER >= TRIO_MSVC_5)
+typedef trio_longlong_t trio_intmax_t;
+typedef trio_ulonglong_t trio_uintmax_t;
+typedef __int8 trio_int8_t;
+typedef __int16 trio_int16_t;
+typedef __int32 trio_int32_t;
+typedef __int64 trio_int64_t;
+#else
+typedef trio_longlong_t trio_intmax_t;
+typedef trio_ulonglong_t trio_uintmax_t;
+# if defined(TRIO_INT8_T)
+typedef TRIO_INT8_T trio_int8_t;
+# else
+typedef signed char trio_int8_t;
+# endif
+# if defined(TRIO_INT16_T)
+typedef TRIO_INT16_T trio_int16_t;
+# else
+typedef signed short trio_int16_t;
+# endif
+# if defined(TRIO_INT32_T)
+typedef TRIO_INT32_T trio_int32_t;
+# else
+typedef signed int trio_int32_t;
+# endif
+# if defined(TRIO_INT64_T)
+typedef TRIO_INT64_T trio_int64_t;
+# else
+typedef trio_longlong_t trio_int64_t;
+# endif
+#endif
+
+
+/*************************************************************************
+ * Internal definitions
+ */
+
+/* Long double sizes */
+#ifdef LDBL_DIG
+# define MAX_MANTISSA_DIGITS LDBL_DIG
+# define MAX_EXPONENT_DIGITS 4
+#else
+# define MAX_MANTISSA_DIGITS DBL_DIG
+# define MAX_EXPONENT_DIGITS 3
+#endif
+
+/* The maximal number of digits is for base 2 */
+#define MAX_CHARS_IN(x) (sizeof(x) * CHAR_BIT)
+/* The width of a pointer. The number of bits in a hex digit is 4 */
+#define POINTER_WIDTH ((sizeof("0x") - 1) + sizeof(void *) * CHAR_BIT / 4)
+
+/* Infinite and Not-A-Number for floating-point */
+#define INFINITE_LOWER "inf"
+#define INFINITE_UPPER "INF"
+#define LONG_INFINITE_LOWER "infinite"
+#define LONG_INFINITE_UPPER "INFINITE"
+#define NAN_LOWER "nan"
+#define NAN_UPPER "NAN"
+
+/* Various constants */
+enum {
+ TYPE_PRINT = 1,
+ TYPE_SCAN = 2,
+
+ /* Flags. Use maximum 32 */
+ FLAGS_NEW = 0,
+ FLAGS_STICKY = 1,
+ FLAGS_SPACE = 2 * FLAGS_STICKY,
+ FLAGS_SHOWSIGN = 2 * FLAGS_SPACE,
+ FLAGS_LEFTADJUST = 2 * FLAGS_SHOWSIGN,
+ FLAGS_ALTERNATIVE = 2 * FLAGS_LEFTADJUST,
+ FLAGS_SHORT = 2 * FLAGS_ALTERNATIVE,
+ FLAGS_SHORTSHORT = 2 * FLAGS_SHORT,
+ FLAGS_LONG = 2 * FLAGS_SHORTSHORT,
+ FLAGS_QUAD = 2 * FLAGS_LONG,
+ FLAGS_LONGDOUBLE = 2 * FLAGS_QUAD,
+ FLAGS_SIZE_T = 2 * FLAGS_LONGDOUBLE,
+ FLAGS_PTRDIFF_T = 2 * FLAGS_SIZE_T,
+ FLAGS_INTMAX_T = 2 * FLAGS_PTRDIFF_T,
+ FLAGS_NILPADDING = 2 * FLAGS_INTMAX_T,
+ FLAGS_UNSIGNED = 2 * FLAGS_NILPADDING,
+ FLAGS_UPPER = 2 * FLAGS_UNSIGNED,
+ FLAGS_WIDTH = 2 * FLAGS_UPPER,
+ FLAGS_WIDTH_PARAMETER = 2 * FLAGS_WIDTH,
+ FLAGS_PRECISION = 2 * FLAGS_WIDTH_PARAMETER,
+ FLAGS_PRECISION_PARAMETER = 2 * FLAGS_PRECISION,
+ FLAGS_BASE = 2 * FLAGS_PRECISION_PARAMETER,
+ FLAGS_BASE_PARAMETER = 2 * FLAGS_BASE,
+ FLAGS_FLOAT_E = 2 * FLAGS_BASE_PARAMETER,
+ FLAGS_FLOAT_G = 2 * FLAGS_FLOAT_E,
+ FLAGS_QUOTE = 2 * FLAGS_FLOAT_G,
+ FLAGS_WIDECHAR = 2 * FLAGS_QUOTE,
+ FLAGS_ALLOC = 2 * FLAGS_WIDECHAR,
+ FLAGS_IGNORE = 2 * FLAGS_ALLOC,
+ FLAGS_IGNORE_PARAMETER = 2 * FLAGS_IGNORE,
+ FLAGS_VARSIZE_PARAMETER = 2 * FLAGS_IGNORE_PARAMETER,
+ FLAGS_FIXED_SIZE = 2 * FLAGS_VARSIZE_PARAMETER,
+ /* Reused flags */
+ FLAGS_EXCLUDE = FLAGS_SHORT,
+ FLAGS_USER_DEFINED = FLAGS_IGNORE,
+ /* Compounded flags */
+ FLAGS_ALL_VARSIZES = FLAGS_LONG | FLAGS_QUAD | FLAGS_INTMAX_T | FLAGS_PTRDIFF_T | FLAGS_SIZE_T,
+ FLAGS_ALL_SIZES = FLAGS_ALL_VARSIZES | FLAGS_SHORTSHORT | FLAGS_SHORT,
+
+ NO_POSITION = -1,
+ NO_WIDTH = 0,
+ NO_PRECISION = -1,
+ NO_SIZE = -1,
+
+ NO_BASE = -1,
+ MIN_BASE = 2,
+ MAX_BASE = 36,
+ BASE_BINARY = 2,
+ BASE_OCTAL = 8,
+ BASE_DECIMAL = 10,
+ BASE_HEX = 16,
+
+ /* Maximal number of allowed parameters */
+ MAX_PARAMETERS = 64,
+ /* Maximal number of characters in class */
+ MAX_CHARACTER_CLASS = UCHAR_MAX,
+
+ /* Maximal string lengths for user-defined specifiers */
+ MAX_USER_NAME = 64,
+ MAX_USER_DATA = 256,
+
+ /* Maximal length of locale separator strings */
+ MAX_LOCALE_SEPARATOR_LENGTH = MB_LEN_MAX,
+ /* Maximal number of integers in grouping */
+ MAX_LOCALE_GROUPS = 64
+};
+
+#define NO_GROUPING ((int)CHAR_MAX)
+
+/* Fundamental formatting parameter types */
+#define FORMAT_UNKNOWN 0
+#define FORMAT_INT 1
+#define FORMAT_DOUBLE 2
+#define FORMAT_CHAR 3
+#define FORMAT_STRING 4
+#define FORMAT_POINTER 5
+#define FORMAT_COUNT 6
+#define FORMAT_PARAMETER 7
+#define FORMAT_GROUP 8
+#if TRIO_GNU
+# define FORMAT_ERRNO 9
+#endif
+#if TRIO_EXTENSION
+# define FORMAT_USER_DEFINED 10
+#endif
+
+/* Character constants */
+#define CHAR_IDENTIFIER '%'
+#define CHAR_BACKSLASH '\\'
+#define CHAR_QUOTE '\"'
+#define CHAR_ADJUST ' '
+
+/* Character class expressions */
+#define CLASS_ALNUM ":alnum:"
+#define CLASS_ALPHA ":alpha:"
+#define CLASS_CNTRL ":cntrl:"
+#define CLASS_DIGIT ":digit:"
+#define CLASS_GRAPH ":graph:"
+#define CLASS_LOWER ":lower:"
+#define CLASS_PRINT ":print:"
+#define CLASS_PUNCT ":punct:"
+#define CLASS_SPACE ":space:"
+#define CLASS_UPPER ":upper:"
+#define CLASS_XDIGIT ":xdigit:"
+
+/*
+ * SPECIFIERS:
+ *
+ *
+ * a Hex-float
+ * A Hex-float
+ * c Character
+ * C Widechar character (wint_t)
+ * d Decimal
+ * e Float
+ * E Float
+ * F Float
+ * F Float
+ * g Float
+ * G Float
+ * i Integer
+ * m Error message
+ * n Count
+ * o Octal
+ * p Pointer
+ * s String
+ * S Widechar string (wchar_t *)
+ * u Unsigned
+ * x Hex
+ * X Hex
+ * [] Group
+ * <> User-defined
+ *
+ * Reserved:
+ *
+ * D Binary Coded Decimal %D(length,precision) (OS/390)
+ */
+#define SPECIFIER_CHAR 'c'
+#define SPECIFIER_STRING 's'
+#define SPECIFIER_DECIMAL 'd'
+#define SPECIFIER_INTEGER 'i'
+#define SPECIFIER_UNSIGNED 'u'
+#define SPECIFIER_OCTAL 'o'
+#define SPECIFIER_HEX 'x'
+#define SPECIFIER_HEX_UPPER 'X'
+#define SPECIFIER_FLOAT_E 'e'
+#define SPECIFIER_FLOAT_E_UPPER 'E'
+#define SPECIFIER_FLOAT_F 'f'
+#define SPECIFIER_FLOAT_F_UPPER 'F'
+#define SPECIFIER_FLOAT_G 'g'
+#define SPECIFIER_FLOAT_G_UPPER 'G'
+#define SPECIFIER_POINTER 'p'
+#define SPECIFIER_GROUP '['
+#define SPECIFIER_UNGROUP ']'
+#define SPECIFIER_COUNT 'n'
+#if TRIO_UNIX98
+# define SPECIFIER_CHAR_UPPER 'C'
+# define SPECIFIER_STRING_UPPER 'S'
+#endif
+#if TRIO_C99
+# define SPECIFIER_HEXFLOAT 'a'
+# define SPECIFIER_HEXFLOAT_UPPER 'A'
+#endif
+#if TRIO_GNU
+# define SPECIFIER_ERRNO 'm'
+#endif
+#if TRIO_EXTENSION
+# define SPECIFIER_BINARY 'b'
+# define SPECIFIER_BINARY_UPPER 'B'
+# define SPECIFIER_USER_DEFINED_BEGIN '<'
+# define SPECIFIER_USER_DEFINED_END '>'
+# define SPECIFIER_USER_DEFINED_SEPARATOR ':'
+#endif
+
+/*
+ * QUALIFIERS:
+ *
+ *
+ * Numbers = d,i,o,u,x,X
+ * Float = a,A,e,E,f,F,g,G
+ * String = s
+ * Char = c
+ *
+ *
+ * 9$ Position
+ * Use the 9th parameter. 9 can be any number between 1 and
+ * the maximal argument
+ *
+ * 9 Width
+ * Set width to 9. 9 can be any number, but must not be postfixed
+ * by '$'
+ *
+ * h Short
+ * Numbers:
+ * (unsigned) short int
+ *
+ * hh Short short
+ * Numbers:
+ * (unsigned) char
+ *
+ * l Long
+ * Numbers:
+ * (unsigned) long int
+ * String:
+ * as the S specifier
+ * Char:
+ * as the C specifier
+ *
+ * ll Long Long
+ * Numbers:
+ * (unsigned) long long int
+ *
+ * L Long Double
+ * Float
+ * long double
+ *
+ * # Alternative
+ * Float:
+ * Decimal-point is always present
+ * String:
+ * non-printable characters are handled as \number
+ *
+ * Spacing
+ *
+ * + Sign
+ *
+ * - Alignment
+ *
+ * . Precision
+ *
+ * * Parameter
+ * print: use parameter
+ * scan: no parameter (ignore)
+ *
+ * q Quad
+ *
+ * Z size_t
+ *
+ * w Widechar
+ *
+ * ' Thousands/quote
+ * Numbers:
+ * Integer part grouped in thousands
+ * Binary numbers:
+ * Number grouped in nibbles (4 bits)
+ * String:
+ * Quoted string
+ *
+ * j intmax_t
+ * t prtdiff_t
+ * z size_t
+ *
+ * ! Sticky
+ * @ Parameter (for both print and scan)
+ *
+ * I n-bit Integer
+ * Numbers:
+ * The following options exists
+ * I8 = 8-bit integer
+ * I16 = 16-bit integer
+ * I32 = 32-bit integer
+ * I64 = 64-bit integer
+ */
+#define QUALIFIER_POSITION '$'
+#define QUALIFIER_SHORT 'h'
+#define QUALIFIER_LONG 'l'
+#define QUALIFIER_LONG_UPPER 'L'
+#define QUALIFIER_ALTERNATIVE '#'
+#define QUALIFIER_SPACE ' '
+#define QUALIFIER_PLUS '+'
+#define QUALIFIER_MINUS '-'
+#define QUALIFIER_DOT '.'
+#define QUALIFIER_STAR '*'
+#define QUALIFIER_CIRCUMFLEX '^'
+#if TRIO_C99
+# define QUALIFIER_SIZE_T 'z'
+# define QUALIFIER_PTRDIFF_T 't'
+# define QUALIFIER_INTMAX_T 'j'
+#endif
+#if TRIO_BSD || TRIO_GNU
+# define QUALIFIER_QUAD 'q'
+#endif
+#if TRIO_GNU
+# define QUALIFIER_SIZE_T_UPPER 'Z'
+#endif
+#if TRIO_MISC
+# define QUALIFIER_WIDECHAR 'w'
+#endif
+#if TRIO_MICROSOFT
+# define QUALIFIER_FIXED_SIZE 'I'
+#endif
+#if TRIO_EXTENSION
+# define QUALIFIER_QUOTE '\''
+# define QUALIFIER_STICKY '!'
+# define QUALIFIER_VARSIZE '&' /* This should remain undocumented */
+# define QUALIFIER_PARAM '@' /* Experimental */
+# define QUALIFIER_COLON ':' /* For scanlists */
+# define QUALIFIER_EQUAL '=' /* For scanlists */
+#endif
+#if DATAGRID_EXTENSION
+# define QUALIFIER_ESCAPE '|'
+#endif
+
+
+/*************************************************************************
+ * Internal structures
+ */
+
+/* Parameters */
+typedef struct {
+ int type;
+ unsigned long flags;
+ int width;
+ int precision;
+ int base;
+ int varsize;
+#ifdef QUALIFIER_ESCAPE
+ enum dg_escape { ESCAPE_NONE, ESCAPE_ULM, ESCAPE_XML, ESCAPE_SQL } escape;
+#endif
+ int indexAfterSpecifier;
+ union {
+ char *string;
+#if TRIO_WIDECHAR
+ wchar_t *wstring;
+#endif
+ void *pointer;
+ union {
+ trio_uintmax_t as_signed;
+ trio_intmax_t as_unsigned;
+ } number;
+ double doubleNumber;
+ double *doublePointer;
+ long double longdoubleNumber;
+ long double *longdoublePointer;
+ int errorNumber;
+ } data;
+ /* For the user-defined specifier */
+ char user_name[MAX_USER_NAME];
+ char user_data[MAX_USER_DATA];
+} parameter_T;
+
+/* General trio "class" */
+typedef struct _trio_T {
+ void *location;
+ void (*OutStream)(struct _trio_T *, int);
+ void (*InStream)(struct _trio_T *, int *);
+ /*
+ * The number of characters that would have been written/read if
+ * there had been sufficient space.
+ */
+ int processed;
+ /*
+ * The number of characters that are actually written/read.
+ * Processed and committed with only differ for the *nprintf
+ * and *nscanf functions.
+ */
+ int committed;
+ int max;
+ int current;
+} trio_T;
+
+/* References (for user-defined callbacks) */
+typedef struct _reference_T {
+ trio_T *data;
+ parameter_T *parameter;
+} reference_T;
+
+/* Registered entries (for user-defined callbacks) */
+typedef struct _userdef_T {
+ struct _userdef_T *next;
+ trio_callback_t callback;
+ char *name;
+} userdef_T;
+
+
+/*************************************************************************
+ * Internal variables
+ */
+
+static const char null[] = "(nil)";
+
+#if defined(USE_LOCALE)
+static struct lconv *internalLocaleValues = NULL;
+#endif
+
+/*
+ * UNIX98 says "in a locale where the radix character is not defined,
+ * the radix character defaults to a period (.)"
+ */
+static char internalDecimalPoint[MAX_LOCALE_SEPARATOR_LENGTH + 1] = ".";
+static char internalThousandSeparator[MAX_LOCALE_SEPARATOR_LENGTH + 1] = ",";
+static char internalGrouping[MAX_LOCALE_GROUPS] = { (char)NO_GROUPING };
+
+static const char internalDigitsLower[] = "0123456789abcdefghijklmnopqrstuvwxyz";
+static const char internalDigitsUpper[] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
+static BOOLEAN_T internalDigitsUnconverted = TRUE;
+static int internalDigitArray[128];
+#if TRIO_EXTENSION
+static BOOLEAN_T internalCollationUnconverted = TRUE;
+static char internalCollationArray[MAX_CHARACTER_CLASS][MAX_CHARACTER_CLASS];
+#endif
+
+static volatile trio_callback_t internalEnterCriticalRegion = NULL;
+static volatile trio_callback_t internalLeaveCriticalRegion = NULL;
+static userdef_T *internalUserDef = NULL;
+
+
+/*************************************************************************
+ * trio_strerror [public]
+ */
+const char *trio_strerror(int errorcode)
+{
+ /* Textual versions of the error codes */
+ switch (TRIO_ERROR_CODE(errorcode))
+ {
+ case TRIO_EOF:
+ return "End of file";
+ case TRIO_EINVAL:
+ return "Invalid argument";
+ case TRIO_ETOOMANY:
+ return "Too many arguments";
+ case TRIO_EDBLREF:
+ return "Double reference";
+ case TRIO_EGAP:
+ return "Reference gap";
+ case TRIO_ENOMEM:
+ return "Out of memory";
+ case TRIO_ERANGE:
+ return "Invalid range";
+ default:
+ return "Unknown";
+ }
+}
+
+/*************************************************************************
+ * TrioIsQualifier [private]
+ *
+ * Description:
+ * Remember to add all new qualifiers to this function.
+ * QUALIFIER_POSITION must not be added.
+ */
+static BOOLEAN_T
+TrioIsQualifier(const char ch)
+{
+ /* QUALIFIER_POSITION is not included */
+ switch (ch)
+ {
+ case '0': case '1': case '2': case '3': case '4':
+ case '5': case '6': case '7': case '8': case '9':
+ case QUALIFIER_PLUS:
+ case QUALIFIER_MINUS:
+ case QUALIFIER_SPACE:
+ case QUALIFIER_DOT:
+ case QUALIFIER_STAR:
+ case QUALIFIER_ALTERNATIVE:
+ case QUALIFIER_SHORT:
+ case QUALIFIER_LONG:
+ case QUALIFIER_LONG_UPPER:
+ case QUALIFIER_CIRCUMFLEX:
+#if defined(QUALIFIER_SIZE_T)
+ case QUALIFIER_SIZE_T:
+#endif
+#if defined(QUALIFIER_PTRDIFF_T)
+ case QUALIFIER_PTRDIFF_T:
+#endif
+#if defined(QUALIFIER_INTMAX_T)
+ case QUALIFIER_INTMAX_T:
+#endif
+#if defined(QUALIFIER_QUAD)
+ case QUALIFIER_QUAD:
+#endif
+#if defined(QUALIFIER_SIZE_T_UPPER)
+ case QUALIFIER_SIZE_T_UPPER:
+#endif
+#if defined(QUALIFIER_WIDECHAR)
+ case QUALIFIER_WIDECHAR:
+#endif
+#if defined(QUALIFIER_QUOTE)
+ case QUALIFIER_QUOTE:
+#endif
+#if defined(QUALIFIER_STICKY)
+ case QUALIFIER_STICKY:
+#endif
+#if defined(QUALIFIER_VARSIZE)
+ case QUALIFIER_VARSIZE:
+#endif
+#if defined(QUALIFIER_PARAM)
+ case QUALIFIER_PARAM:
+#endif
+#if defined(QUALIFIER_FIXED_SIZE)
+ case QUALIFIER_FIXED_SIZE:
+#endif
+#ifdef QUALIFIER_ESCAPE
+ case QUALIFIER_ESCAPE:
+#endif
+ return TRUE;
+ default:
+ return FALSE;
+ }
+}
+
+/*************************************************************************
+ * TrioGenerateNan [private]
+ *
+ * Calculating NaN portably is difficult. Some compilers will emit
+ * warnings about divide by zero, and others will simply fail to
+ * generate a NaN.
+ */
+static double
+TrioGenerateNaN(void)
+{
+#if defined(TRIO_COMPILER_SUPPORTS_C99)
+ return nan(NULL);
+#elif defined(DBL_QNAN)
+ return DBL_QNAN;
+#elif defined(PLATFORM_UNIX)
+ double value;
+ void (*signal_handler)(int);
+
+ signal_handler = signal(SIGFPE, SIG_IGN);
+ value = 0.0 / 0.0;
+ signal(SIGFPE, signal_handler);
+ return value;
+#else
+ return 0.0 / 0.0;
+#endif
+}
+
+/*************************************************************************
+ * TrioIsNan [private]
+ */
+static int
+TrioIsNan(double number)
+{
+#ifdef isnan
+ /* C99 defines isnan() as a macro */
+ return isnan(number);
+#else
+ double integral, fraction;
+
+ return (/* NaN is the only number which does not compare to itself */
+ (number != number) ||
+ /* Fallback solution if NaN compares to NaN */
+ ((number != 0.0) &&
+ (fraction = modf(number, &integral),
+ integral == fraction)));
+#endif
+}
+
+/*************************************************************************
+ * TrioIsInfinite [private]
+ */
+static int
+TrioIsInfinite(double number)
+{
+#ifdef isinf
+ /* C99 defines isinf() as a macro */
+ return isinf(number);
+#else
+ return ((number == HUGE_VAL) ? 1 : ((number == -HUGE_VAL) ? -1 : 0));
+#endif
+}
+
+/*************************************************************************
+ * TrioSetLocale [private]
+ */
+#if defined(USE_LOCALE)
+static void
+TrioSetLocale(void)
+{
+ internalLocaleValues = (struct lconv *)localeconv();
+ if (internalLocaleValues)
+ {
+ if ((internalLocaleValues->decimal_point) &&
+ (internalLocaleValues->decimal_point[0] != NIL))
+ {
+ StrCopyMax(internalDecimalPoint,
+ sizeof(internalDecimalPoint),
+ internalLocaleValues->decimal_point);
+ }
+ if ((internalLocaleValues->thousands_sep) &&
+ (internalLocaleValues->thousands_sep[0] != NIL))
+ {
+ StrCopyMax(internalThousandSeparator,
+ sizeof(internalThousandSeparator),
+ internalLocaleValues->thousands_sep);
+ }
+ if ((internalLocaleValues->grouping) &&
+ (internalLocaleValues->grouping[0] != NIL))
+ {
+ StrCopyMax(internalGrouping,
+ sizeof(internalGrouping),
+ internalLocaleValues->grouping);
+ }
+ }
+}
+#endif /* defined(USE_LOCALE) */
+
+/*************************************************************************
+ * TrioGetPosition [private]
+ *
+ * Get the %n$ position.
+ */
+static int
+TrioGetPosition(const char *format,
+ int *indexPointer)
+{
+ char *tmpformat;
+ int number = 0;
+ int index = *indexPointer;
+
+ number = (int)StrToLong(&format[index], &tmpformat, BASE_DECIMAL);
+ index = (int)(tmpformat - format);
+ if ((number != 0) && (QUALIFIER_POSITION == format[index++]))
+ {
+ *indexPointer = index;
+ /*
+ * number is decreased by 1, because n$ starts from 1, whereas
+ * the array it is indexing starts from 0.
+ */
+ return number - 1;
+ }
+ return NO_POSITION;
+}
+
+/*************************************************************************
+ * TrioFindNamespace [private]
+ *
+ * Find registered user-defined specifier.
+ * The prev argument is used for optimisation only.
+ */
+static userdef_T *
+TrioFindNamespace(const char *name, userdef_T **prev)
+{
+ userdef_T *def;
+
+ if (internalEnterCriticalRegion)
+ (void)internalEnterCriticalRegion(NULL);
+
+ for (def = internalUserDef; def; def = def->next)
+ {
+ /* Case-sensitive string comparison */
+ if (StrEqualCase(def->name, name))
+ break;
+
+ if (prev)
+ *prev = def;
+ }
+
+ if (internalLeaveCriticalRegion)
+ (void)internalLeaveCriticalRegion(NULL);
+
+ return def;
+}
+
+/*************************************************************************
+ * TrioPreprocess [private]
+ *
+ * Description:
+ * Parse the format string
+ */
+static int
+TrioPreprocess(int type,
+ const char *format,
+ parameter_T *parameters,
+ va_list arglist,
+ void **argarray)
+{
+#if TRIO_ERRORS
+ /* Count the number of times a parameter is referenced */
+ unsigned short usedEntries[MAX_PARAMETERS];
+#endif
+ /* Parameter counters */
+ int parameterPosition;
+ int currentParam;
+ int maxParam = -1;
+ /* Utility variables */
+ unsigned long flags;
+ int width;
+ int precision;
+ int varsize;
+#ifdef QUALIFIER_ESCAPE
+ enum dg_escape escape;
+#endif
+ int base;
+ int index; /* Index into formatting string */
+ int dots; /* Count number of dots in modifier part */
+ BOOLEAN_T positional; /* Does the specifier have a positional? */
+ BOOLEAN_T got_sticky = FALSE; /* Are there any sticky modifiers at all? */
+ /*
+ * indices specifies the order in which the parameters must be
+ * read from the va_args (this is necessary to handle positionals)
+ */
+ int indices[MAX_PARAMETERS];
+ int pos = 0;
+ /* Various variables */
+ char ch;
+#if defined(TRIO_COMPILER_SUPPORTS_MULTIBYTE)
+ int charlen;
+#endif
+ int i = -1;
+ int num;
+ char *tmpformat;
+
+
+#if TRIO_ERRORS
+ /*
+ * The 'parameters' array is not initialized, but we need to
+ * know which entries we have used.
+ */
+ memset(usedEntries, 0, sizeof(usedEntries));
+#endif
+
+ index = 0;
+ parameterPosition = 0;
+#if defined(TRIO_COMPILER_SUPPORTS_MULTIBYTE)
+ mblen(NULL, 0);
+#endif
+
+ while (format[index])
+ {
+#if defined(TRIO_COMPILER_SUPPORTS_MULTIBYTE)
+ if (! isascii(format[index]))
+ {
+ /*
+ * Multibyte characters cannot be legal specifiers or
+ * modifiers, so we skip over them.
+ */
+ charlen = mblen(&format[index], MB_LEN_MAX);
+ index += (charlen > 0) ? charlen : 1;
+ continue; /* while */
+ }
+#endif /* TRIO_COMPILER_SUPPORTS_MULTIBYTE */
+ if (CHAR_IDENTIFIER == format[index++])
+ {
+ if (CHAR_IDENTIFIER == format[index])
+ {
+ index++;
+ continue; /* while */
+ }
+
+ flags = FLAGS_NEW;
+ dots = 0;
+ currentParam = TrioGetPosition(format, &index);
+ positional = (NO_POSITION != currentParam);
+ if (!positional)
+ {
+ /* We have no positional, get the next counter */
+ currentParam = parameterPosition;
+ }
+ if(currentParam >= MAX_PARAMETERS)
+ {
+ /* Bail out completely to make the error more obvious */
+ return TRIO_ERROR_RETURN(TRIO_ETOOMANY, index);
+ }
+
+ if (currentParam > maxParam)
+ maxParam = currentParam;
+
+ /* Default values */
+ width = NO_WIDTH;
+ precision = NO_PRECISION;
+ base = NO_BASE;
+ varsize = NO_SIZE;
+#ifdef QUALIFIER_ESCAPE
+ escape = ESCAPE_NONE;
+#endif
+
+ while (TrioIsQualifier(format[index]))
+ {
+ ch = format[index++];
+
+ switch (ch)
+ {
+ case QUALIFIER_SPACE:
+ flags |= FLAGS_SPACE;
+ break;
+
+ case QUALIFIER_PLUS:
+ flags |= FLAGS_SHOWSIGN;
+ break;
+
+ case QUALIFIER_MINUS:
+ flags |= FLAGS_LEFTADJUST;
+ flags &= ~FLAGS_NILPADDING;
+ break;
+
+ case QUALIFIER_ALTERNATIVE:
+ flags |= FLAGS_ALTERNATIVE;
+ break;
+
+ case QUALIFIER_DOT:
+ if (dots == 0) /* Precision */
+ {
+ dots++;
+
+ /* Skip if no precision */
+ if (QUALIFIER_DOT == format[index])
+ break;
+
+ /* After the first dot we have the precision */
+ flags |= FLAGS_PRECISION;
+ if ((QUALIFIER_STAR == format[index]) ||
+ (QUALIFIER_PARAM == format[index]))
+ {
+ index++;
+ flags |= FLAGS_PRECISION_PARAMETER;
+
+ precision = TrioGetPosition(format, &index);
+ if (precision == NO_POSITION)
+ {
+ parameterPosition++;
+ if (positional)
+ precision = parameterPosition;
+ else
+ {
+ precision = currentParam;
+ currentParam = precision + 1;
+ }
+ }
+ else
+ {
+ if (! positional)
+ currentParam = precision + 1;
+ if (width > maxParam)
+ maxParam = precision;
+ }
+ if (currentParam > maxParam)
+ maxParam = currentParam;
+ }
+ else
+ {
+ precision = StrToLong(&format[index], &tmpformat, BASE_DECIMAL);
+ index = (int)(tmpformat - format);
+ }
+ }
+ else if (dots == 1) /* Base */
+ {
+ dots++;
+
+ /* After the second dot we have the base */
+ flags |= FLAGS_BASE;
+ if ((QUALIFIER_STAR == format[index]) ||
+ (QUALIFIER_PARAM == format[index]))
+ {
+ index++;
+ flags |= FLAGS_BASE_PARAMETER;
+ base = TrioGetPosition(format, &index);
+ if (base == NO_POSITION)
+ {
+ parameterPosition++;
+ if (positional)
+ base = parameterPosition;
+ else
+ {
+ base = currentParam;
+ currentParam = base + 1;
+ }
+ }
+ else
+ {
+ if (! positional)
+ currentParam = base + 1;
+ if (base > maxParam)
+ maxParam = base;
+ }
+ if (currentParam > maxParam)
+ maxParam = currentParam;
+ }
+ else
+ {
+ base = StrToLong(&format[index], &tmpformat, BASE_DECIMAL);
+ if (base > MAX_BASE)
+ return TRIO_ERROR_RETURN(TRIO_EINVAL, index);
+ index = (int)(tmpformat - format);
+ }
+ }
+ else
+ {
+ return TRIO_ERROR_RETURN(TRIO_EINVAL, index);
+ }
+ break; /* QUALIFIER_DOT */
+
+ case QUALIFIER_PARAM:
+ type = TYPE_PRINT;
+ /* FALLTHROUGH */
+ case QUALIFIER_STAR:
+ /* This has different meanings for print and scan */
+ if (TYPE_PRINT == type)
+ {
+ /* Read with from parameter */
+ flags |= (FLAGS_WIDTH | FLAGS_WIDTH_PARAMETER);
+ width = TrioGetPosition(format, &index);
+ if (width == NO_POSITION)
+ {
+ parameterPosition++;
+ if (positional)
+ width = parameterPosition;
+ else
+ {
+ width = currentParam;
+ currentParam = width + 1;
+ }
+ }
+ else
+ {
+ if (! positional)
+ currentParam = width + 1;
+ if (width > maxParam)
+ maxParam = width;
+ }
+ if (currentParam > maxParam)
+ maxParam = currentParam;
+ }
+ else
+ {
+ /* Scan, but do not store result */
+ flags |= FLAGS_IGNORE;
+ }
+
+ break; /* QUALIFIER_STAR */
+
+ case '0':
+ if (! (flags & FLAGS_LEFTADJUST))
+ flags |= FLAGS_NILPADDING;
+ /* FALLTHROUGH */
+ case '1': case '2': case '3': case '4':
+ case '5': case '6': case '7': case '8': case '9':
+ flags |= FLAGS_WIDTH;
+ /* &format[index - 1] is used to "rewind" the read
+ * character from format
+ */
+ width = StrToLong(&format[index - 1], &tmpformat, BASE_DECIMAL);
+ index = (int)(tmpformat - format);
+ break;
+
+ case QUALIFIER_SHORT:
+ if (flags & FLAGS_SHORTSHORT)
+ return TRIO_ERROR_RETURN(TRIO_EINVAL, index);
+ else if (flags & FLAGS_SHORT)
+ flags |= FLAGS_SHORTSHORT;
+ else
+ flags |= FLAGS_SHORT;
+ break;
+
+ case QUALIFIER_LONG:
+ if (flags & FLAGS_QUAD)
+ return TRIO_ERROR_RETURN(TRIO_EINVAL, index);
+ else if (flags & FLAGS_LONG)
+ flags |= FLAGS_QUAD;
+ else
+ flags |= FLAGS_LONG;
+ break;
+
+ case QUALIFIER_LONG_UPPER:
+ flags |= FLAGS_LONGDOUBLE;
+ break;
+
+#if defined(QUALIFIER_SIZE_T)
+ case QUALIFIER_SIZE_T:
+ flags |= FLAGS_SIZE_T;
+ /* Modify flags for later truncation of number */
+ if (sizeof(size_t) == sizeof(trio_ulonglong_t))
+ flags |= FLAGS_QUAD;
+ else if (sizeof(size_t) == sizeof(long))
+ flags |= FLAGS_LONG;
+ break;
+#endif
+
+#if defined(QUALIFIER_PTRDIFF_T)
+ case QUALIFIER_PTRDIFF_T:
+ flags |= FLAGS_PTRDIFF_T;
+ if (sizeof(ptrdiff_t) == sizeof(trio_ulonglong_t))
+ flags |= FLAGS_QUAD;
+ else if (sizeof(ptrdiff_t) == sizeof(long))
+ flags |= FLAGS_LONG;
+ break;
+#endif
+
+#if defined(QUALIFIER_INTMAX_T)
+ case QUALIFIER_INTMAX_T:
+ flags |= FLAGS_INTMAX_T;
+ if (sizeof(trio_intmax_t) == sizeof(trio_ulonglong_t))
+ flags |= FLAGS_QUAD;
+ else if (sizeof(trio_intmax_t) == sizeof(long))
+ flags |= FLAGS_LONG;
+ break;
+#endif
+
+#if defined(QUALIFIER_QUAD)
+ case QUALIFIER_QUAD:
+ flags |= FLAGS_QUAD;
+ break;
+#endif
+
+#if defined(QUALIFIER_FIXED_SIZE)
+ case QUALIFIER_FIXED_SIZE:
+ if (flags & FLAGS_FIXED_SIZE)
+ return TRIO_ERROR_RETURN(TRIO_EINVAL, index);
+
+ if (flags & (FLAGS_ALL_SIZES | FLAGS_LONGDOUBLE |
+ FLAGS_WIDECHAR | FLAGS_VARSIZE_PARAMETER))
+ return TRIO_ERROR_RETURN(TRIO_EINVAL, index);
+
+ if ((format[index] == '6') &&
+ (format[index + 1] == '4'))
+ {
+ varsize = sizeof(trio_int64_t);
+ index += 2;
+ }
+ else if ((format[index] == '3') &&
+ (format[index + 1] == '2'))
+ {
+ varsize = sizeof(trio_int32_t);
+ index += 2;
+ }
+ else if ((format[index] == '1') &&
+ (format[index + 1] == '6'))
+ {
+ varsize = sizeof(trio_int16_t);
+ index += 2;
+ }
+ else if (format[index] == '8')
+ {
+ varsize = sizeof(trio_int8_t);
+ index++;
+ }
+ else
+ return TRIO_ERROR_RETURN(TRIO_EINVAL, index);
+
+ flags |= FLAGS_FIXED_SIZE;
+ break;
+#endif
+
+#ifdef QUALIFIER_ESCAPE
+ case QUALIFIER_ESCAPE:
+ switch (format[index++]) {
+ case 'U': escape = ESCAPE_ULM; break;
+ case 'X': escape = ESCAPE_XML; break;
+ case 'S': escape = ESCAPE_SQL; break;
+ default: return TRIO_ERROR_RETURN(TRIO_EINVAL,index);
+ }
+ break;
+#endif
+
+
+#if defined(QUALIFIER_WIDECHAR)
+ case QUALIFIER_WIDECHAR:
+ flags |= FLAGS_WIDECHAR;
+ break;
+#endif
+
+#if defined(QUALIFIER_SIZE_T_UPPER)
+ case QUALIFIER_SIZE_T_UPPER:
+ break;
+#endif
+
+#if defined(QUALIFIER_QUOTE)
+ case QUALIFIER_QUOTE:
+ flags |= FLAGS_QUOTE;
+ break;
+#endif
+
+#if defined(QUALIFIER_STICKY)
+ case QUALIFIER_STICKY:
+ flags |= FLAGS_STICKY;
+ got_sticky = TRUE;
+ break;
+#endif
+
+#if defined(QUALIFIER_VARSIZE)
+ case QUALIFIER_VARSIZE:
+ flags |= FLAGS_VARSIZE_PARAMETER;
+ parameterPosition++;
+ if (positional)
+ varsize = parameterPosition;
+ else
+ {
+ varsize = currentParam;
+ currentParam = varsize + 1;
+ }
+ if (currentParam > maxParam)
+ maxParam = currentParam;
+ break;
+#endif
+
+ default:
+ /* Bail out completely to make the error more obvious */
+ return TRIO_ERROR_RETURN(TRIO_EINVAL, index);
+ }
+ } /* while qualifier */
+
+ /*
+ * Parameters only need the type and value. The value is
+ * read later.
+ */
+ if (flags & FLAGS_WIDTH_PARAMETER)
+ {
+#if TRIO_ERRORS
+ usedEntries[width] += 1;
+#endif
+ parameters[pos].type = FORMAT_PARAMETER;
+ indices[width] = pos;
+ width = pos++;
+ }
+ if (flags & FLAGS_PRECISION_PARAMETER)
+ {
+#if TRIO_ERRORS
+ usedEntries[precision] += 1;
+#endif
+ parameters[pos].type = FORMAT_PARAMETER;
+ indices[precision] = pos;
+ precision = pos++;
+ }
+ if (flags & FLAGS_BASE_PARAMETER)
+ {
+#if TRIO_ERRORS
+ usedEntries[base] += 1;
+#endif
+ parameters[pos].type = FORMAT_PARAMETER;
+ indices[base] = pos;
+ base = pos++;
+ }
+ if (flags & FLAGS_VARSIZE_PARAMETER)
+ {
+#if TRIO_ERRORS
+ usedEntries[varsize] += 1;
+#endif
+ parameters[pos].type = FORMAT_PARAMETER;
+ indices[varsize] = pos;
+ varsize = pos++;
+ }
+
+ indices[currentParam] = pos;
+
+ switch (format[index++])
+ {
+#if defined(SPECIFIER_CHAR_UPPER)
+ case SPECIFIER_CHAR_UPPER:
+ flags |= FLAGS_WIDECHAR;
+ /* FALLTHROUGH */
+#endif
+ case SPECIFIER_CHAR:
+ if (flags & FLAGS_LONG)
+ flags |= FLAGS_WIDECHAR;
+ else if (flags & FLAGS_SHORT)
+ flags &= ~FLAGS_WIDECHAR;
+ parameters[pos].type = FORMAT_CHAR;
+ break;
+
+#if defined(SPECIFIER_STRING_UPPER)
+ case SPECIFIER_STRING_UPPER:
+ flags |= FLAGS_WIDECHAR;
+ /* FALLTHROUGH */
+#endif
+ case SPECIFIER_STRING:
+ if (flags & FLAGS_LONG)
+ flags |= FLAGS_WIDECHAR;
+ else if (flags & FLAGS_SHORT)
+ flags &= ~FLAGS_WIDECHAR;
+ parameters[pos].type = FORMAT_STRING;
+ break;
+
+
+ case SPECIFIER_GROUP:
+ if (TYPE_SCAN == type)
+ {
+ int depth = 1;
+ parameters[pos].type = FORMAT_GROUP;
+ if (format[index] == QUALIFIER_CIRCUMFLEX)
+ index++;
+ if (format[index] == SPECIFIER_UNGROUP)
+ index++;
+ if (format[index] == QUALIFIER_MINUS)
+ index++;
+ /* Skip nested brackets */
+ while (format[index] != NIL)
+ {
+ if (format[index] == SPECIFIER_GROUP)
+ {
+ depth++;
+ }
+ else if (format[index] == SPECIFIER_UNGROUP)
+ {
+ if (--depth <= 0)
+ {
+ index++;
+ break;
+ }
+ }
+ index++;
+ }
+ }
+ break;
+
+ case SPECIFIER_INTEGER:
+ parameters[pos].type = FORMAT_INT;
+ break;
+
+ case SPECIFIER_UNSIGNED:
+ flags |= FLAGS_UNSIGNED;
+ parameters[pos].type = FORMAT_INT;
+ break;
+
+ case SPECIFIER_DECIMAL:
+ /* Disable base modifier */
+ flags &= ~FLAGS_BASE_PARAMETER;
+ base = BASE_DECIMAL;
+ parameters[pos].type = FORMAT_INT;
+ break;
+
+ case SPECIFIER_OCTAL:
+ flags &= ~FLAGS_BASE_PARAMETER;
+ base = BASE_OCTAL;
+ parameters[pos].type = FORMAT_INT;
+ break;
+
+#if defined(SPECIFIER_BINARY)
+ case SPECIFIER_BINARY_UPPER:
+ flags |= FLAGS_UPPER;
+ /* FALLTHROUGH */
+ case SPECIFIER_BINARY:
+ flags |= FLAGS_NILPADDING;
+ flags &= ~FLAGS_BASE_PARAMETER;
+ base = BASE_BINARY;
+ parameters[pos].type = FORMAT_INT;
+ break;
+#endif
+
+ case SPECIFIER_HEX_UPPER:
+ flags |= FLAGS_UPPER;
+ /* FALLTHROUGH */
+ case SPECIFIER_HEX:
+ flags |= FLAGS_UNSIGNED;
+ flags &= ~FLAGS_BASE_PARAMETER;
+ base = BASE_HEX;
+ parameters[pos].type = FORMAT_INT;
+ break;
+
+ case SPECIFIER_FLOAT_E_UPPER:
+ flags |= FLAGS_UPPER;
+ /* FALLTHROUGH */
+ case SPECIFIER_FLOAT_E:
+ flags |= FLAGS_FLOAT_E;
+ parameters[pos].type = FORMAT_DOUBLE;
+ break;
+
+ case SPECIFIER_FLOAT_G_UPPER:
+ flags |= FLAGS_UPPER;
+ /* FALLTHROUGH */
+ case SPECIFIER_FLOAT_G:
+ flags |= FLAGS_FLOAT_G;
+ parameters[pos].type = FORMAT_DOUBLE;
+ break;
+
+ case SPECIFIER_FLOAT_F_UPPER:
+ flags |= FLAGS_UPPER;
+ /* FALLTHROUGH */
+ case SPECIFIER_FLOAT_F:
+ parameters[pos].type = FORMAT_DOUBLE;
+ break;
+
+ case SPECIFIER_POINTER:
+ parameters[pos].type = FORMAT_POINTER;
+ break;
+
+ case SPECIFIER_COUNT:
+ parameters[pos].type = FORMAT_COUNT;
+ break;
+
+#if defined(SPECIFIER_HEXFLOAT)
+# if defined(SPECIFIER_HEXFLOAT_UPPER)
+ case SPECIFIER_HEXFLOAT_UPPER:
+ flags |= FLAGS_UPPER;
+ /* FALLTHROUGH */
+# endif
+ case SPECIFIER_HEXFLOAT:
+ base = BASE_HEX;
+ parameters[pos].type = FORMAT_DOUBLE;
+ break;
+#endif
+
+#if defined(FORMAT_ERRNO)
+ case SPECIFIER_ERRNO:
+ parameters[pos].type = FORMAT_ERRNO;
+ break;
+#endif
+
+#if defined(SPECIFIER_USER_DEFINED_BEGIN)
+ case SPECIFIER_USER_DEFINED_BEGIN:
+ {
+ unsigned int max;
+ int without_namespace = TRUE;
+
+ parameters[pos].type = FORMAT_USER_DEFINED;
+ parameters[pos].user_name[0] = NIL;
+ tmpformat = (char *)&format[index];
+
+ while ((ch = format[index]))
+ {
+ index++;
+ if (ch == SPECIFIER_USER_DEFINED_END)
+ {
+ if (without_namespace)
+ {
+ /* We must get the handle first */
+ parameters[pos].type = FORMAT_PARAMETER;
+ parameters[pos].indexAfterSpecifier = index;
+ parameters[pos].flags = FLAGS_USER_DEFINED;
+ /* Adjust parameters for insertion of new one */
+ pos++;
+# if TRIO_ERRORS
+ usedEntries[currentParam] += 1;
+# endif
+ parameters[pos].type = FORMAT_USER_DEFINED;
+ currentParam++;
+ indices[currentParam] = pos;
+ if (currentParam > maxParam)
+ maxParam = currentParam;
+ }
+ /* Copy the user data */
+ max = (unsigned int)(&format[index] - tmpformat);
+ if (max > MAX_USER_DATA)
+ max = MAX_USER_DATA;
+ StrCopyMax(parameters[pos].user_data,
+ max,
+ tmpformat);
+ break; /* while */
+ }
+ if (ch == SPECIFIER_USER_DEFINED_SEPARATOR)
+ {
+ without_namespace = FALSE;
+ /* Copy the namespace for later looking-up */
+ max = (int)(&format[index] - tmpformat);
+ if (max > MAX_USER_NAME)
+ max = MAX_USER_NAME;
+ StrCopyMax(parameters[pos].user_name,
+ max,
+ tmpformat);
+ tmpformat = (char *)&format[index];
+ }
+ }
+ if (ch != SPECIFIER_USER_DEFINED_END)
+ return TRIO_ERROR_RETURN(TRIO_EINVAL, index);
+ }
+ break;
+#endif /* defined(SPECIFIER_USER_DEFINED_BEGIN) */
+
+ default:
+ /* Bail out completely to make the error more obvious */
+ return TRIO_ERROR_RETURN(TRIO_EINVAL, index);
+ }
+
+#if TRIO_ERRORS
+ /* Count the number of times this entry has been used */
+ usedEntries[currentParam] += 1;
+#endif
+
+ /* Find last sticky parameters */
+ if (got_sticky && !(flags & FLAGS_STICKY))
+ {
+ for (i = pos - 1; i >= 0; i--)
+ {
+ if (parameters[i].type == FORMAT_PARAMETER)
+ continue;
+ if ((parameters[i].flags & FLAGS_STICKY) &&
+ (parameters[i].type == parameters[pos].type))
+ {
+ /* Do not overwrite current qualifiers */
+ flags |= (parameters[i].flags & (unsigned long)~FLAGS_STICKY);
+ if (width == NO_WIDTH)
+ width = parameters[i].width;
+ if (precision == NO_PRECISION)
+ precision = parameters[i].precision;
+ if (base == NO_BASE)
+ base = parameters[i].base;
+ break;
+ }
+ }
+ }
+
+ parameters[pos].indexAfterSpecifier = index;
+ parameters[pos].flags = flags;
+ parameters[pos].width = width;
+ parameters[pos].precision = precision;
+ parameters[pos].base = (base == NO_BASE) ? BASE_DECIMAL : base;
+ parameters[pos].varsize = varsize;
+#ifdef QUALIFIER_ESCAPE
+ parameters[pos].escape = escape;
+#endif
+ pos++;
+
+ if (! positional)
+ parameterPosition++;
+
+ } /* if identifier */
+
+ } /* while format characters left */
+
+ for (num = 0; num <= maxParam; num++)
+ {
+#if TRIO_ERRORS
+ if (usedEntries[num] != 1)
+ {
+ if (usedEntries[num] == 0) /* gap detected */
+ return TRIO_ERROR_RETURN(TRIO_EGAP, num);
+ else /* double references detected */
+ return TRIO_ERROR_RETURN(TRIO_EDBLREF, num);
+ }
+#endif
+
+ i = indices[num];
+
+ /*
+ * FORMAT_PARAMETERS are only present if they must be read,
+ * so it makes no sense to check the ignore flag (besides,
+ * the flags variable is not set for that particular type)
+ */
+ if ((parameters[i].type != FORMAT_PARAMETER) &&
+ (parameters[i].flags & FLAGS_IGNORE))
+ continue; /* for all arguments */
+
+ /*
+ * The stack arguments are read according to ANSI C89
+ * default argument promotions:
+ *
+ * char = int
+ * short = int
+ * unsigned char = unsigned int
+ * unsigned short = unsigned int
+ * float = double
+ *
+ * In addition to the ANSI C89 these types are read (the
+ * default argument promotions of C99 has not been
+ * considered yet)
+ *
+ * long long
+ * long double
+ * size_t
+ * ptrdiff_t
+ * intmax_t
+ */
+ switch (parameters[i].type)
+ {
+ case FORMAT_GROUP:
+ case FORMAT_STRING:
+#if TRIO_WIDECHAR
+ if (flags & FLAGS_WIDECHAR)
+ {
+ parameters[i].data.wstring = (argarray == NULL)
+ ? va_arg(arglist, wchar_t *)
+ : (wchar_t *)(argarray[num]);
+ }
+ else
+#endif
+ {
+ parameters[i].data.string = (argarray == NULL)
+ ? va_arg(arglist, char *)
+ : (char *)(argarray[num]);
+ }
+ break;
+
+ case FORMAT_POINTER:
+ case FORMAT_COUNT:
+ case FORMAT_USER_DEFINED:
+ case FORMAT_UNKNOWN:
+ parameters[i].data.pointer = (argarray == NULL)
+ ? va_arg(arglist, void *)
+ : argarray[num];
+ break;
+
+ case FORMAT_CHAR:
+ case FORMAT_INT:
+ if (TYPE_SCAN == type)
+ {
+ if (argarray == NULL)
+ parameters[i].data.pointer =
+ (trio_uintmax_t *)va_arg(arglist, void *);
+ else
+ {
+ if (parameters[i].type == FORMAT_CHAR)
+ parameters[i].data.pointer =
+ (trio_uintmax_t *)((char *)argarray[num]);
+ else if (parameters[i].flags & FLAGS_SHORT)
+ parameters[i].data.pointer =
+ (trio_uintmax_t *)((short *)argarray[num]);
+ else
+ parameters[i].data.pointer =
+ (trio_uintmax_t *)((int *)argarray[num]);
+ }
+ }
+ else
+ {
+#if defined(QUALIFIER_VARSIZE) || defined(QUALIFIER_FIXED_SIZE)
+ if ((parameters[i].flags & FLAGS_VARSIZE_PARAMETER) ||
+ (parameters[i].flags & FLAGS_FIXED_SIZE))
+ {
+ if (parameters[i].flags & FLAGS_VARSIZE_PARAMETER)
+ {
+ /*
+ * Variable sizes are mapped onto the fixed sizes, in
+ * accordance with integer promotion.
+ *
+ * Please note that this may not be portable, as we
+ * only guess the size, not the layout of the numbers.
+ * For example, if int is little-endian, and long is
+ * big-endian, then this will fail.
+ */
+ varsize = (int)parameters[parameters[i].varsize].data.number.as_unsigned;
+ }
+ else
+ {
+ /* Used for the I<bits> modifiers */
+ varsize = parameters[i].varsize;
+ }
+ parameters[i].flags &= ~FLAGS_ALL_VARSIZES;
+
+ if (varsize <= (int)sizeof(int))
+ ;
+ else if (varsize <= (int)sizeof(long))
+ parameters[i].flags |= FLAGS_LONG;
+#if defined(QUALIFIER_INTMAX_T)
+ else if (varsize <= (int)sizeof(trio_longlong_t))
+ parameters[i].flags |= FLAGS_QUAD;
+ else
+ parameters[i].flags |= FLAGS_INTMAX_T;
+#else
+ else
+ parameters[i].flags |= FLAGS_QUAD;
+#endif
+ }
+#endif /* defined(QUALIFIER_VARSIZE) */
+#if defined(QUALIFIER_SIZE_T) || defined(QUALIFIER_SIZE_T_UPPER)
+ if (parameters[i].flags & FLAGS_SIZE_T)
+ parameters[i].data.number.as_unsigned = (argarray == NULL)
+ ? (trio_uintmax_t)va_arg(arglist, size_t)
+ : (trio_uintmax_t)(*((size_t *)argarray[num]));
+ else
+#endif
+#if defined(QUALIFIER_PTRDIFF_T)
+ if (parameters[i].flags & FLAGS_PTRDIFF_T)
+ parameters[i].data.number.as_unsigned = (argarray == NULL)
+ ? (trio_uintmax_t)va_arg(arglist, ptrdiff_t)
+ : (trio_uintmax_t)(*((ptrdiff_t *)argarray[num]));
+ else
+#endif
+#if defined(QUALIFIER_INTMAX_T)
+ if (parameters[i].flags & FLAGS_INTMAX_T)
+ parameters[i].data.number.as_unsigned = (argarray == NULL)
+ ? (trio_uintmax_t)va_arg(arglist, trio_intmax_t)
+ : (trio_uintmax_t)(*((trio_intmax_t *)argarray[num]));
+ else
+#endif
+ if (parameters[i].flags & FLAGS_QUAD)
+ parameters[i].data.number.as_unsigned = (argarray == NULL)
+ ? (trio_uintmax_t)va_arg(arglist, trio_ulonglong_t)
+ : (trio_uintmax_t)(*((trio_ulonglong_t *)argarray[num]));
+ else if (parameters[i].flags & FLAGS_LONG)
+ parameters[i].data.number.as_unsigned = (argarray == NULL)
+ ? (trio_uintmax_t)va_arg(arglist, long)
+ : (trio_uintmax_t)(*((long *)argarray[num]));
+ else
+ {
+ if (argarray == NULL)
+ parameters[i].data.number.as_unsigned = (trio_uintmax_t)va_arg(arglist, int);
+ else
+ {
+ if (parameters[i].type == FORMAT_CHAR)
+ parameters[i].data.number.as_unsigned = (trio_uintmax_t)(*((char *)argarray[num]));
+ else if (parameters[i].flags & FLAGS_SHORT)
+ parameters[i].data.number.as_unsigned = (trio_uintmax_t)(*((short *)argarray[num]));
+ else
+ parameters[i].data.number.as_unsigned = (trio_uintmax_t)(*((int *)argarray[num]));
+ }
+ }
+ }
+ break;
+
+ case FORMAT_PARAMETER:
+ /*
+ * The parameter for the user-defined specifier is a pointer,
+ * whereas the rest (width, precision, base) uses an integer.
+ */
+ if (parameters[i].flags & FLAGS_USER_DEFINED)
+ parameters[i].data.pointer = (argarray == NULL)
+ ? va_arg(arglist, void *)
+ : argarray[num];
+ else
+ parameters[i].data.number.as_unsigned = (argarray == NULL)
+ ? (trio_uintmax_t)va_arg(arglist, int)
+ : (trio_uintmax_t)(*((int *)argarray[num]));
+ break;
+
+ case FORMAT_DOUBLE:
+ if (TYPE_SCAN == type)
+ {
+ if (parameters[i].flags & FLAGS_LONG)
+ parameters[i].data.longdoublePointer = (argarray == NULL)
+ ? va_arg(arglist, long double *)
+ : (long double *)((long double *)argarray[num]);
+ else
+ {
+ if (argarray == NULL)
+ parameters[i].data.doublePointer =
+ va_arg(arglist, double *);
+ else
+ {
+ if (parameters[i].flags & FLAGS_SHORT)
+ parameters[i].data.doublePointer =
+ (double *)((float *)argarray[num]);
+ else
+ parameters[i].data.doublePointer =
+ (double *)((double *)argarray[num]);
+ }
+ }
+ }
+ else
+ {
+ if (parameters[i].flags & FLAGS_LONG)
+ parameters[i].data.longdoubleNumber = (argarray == NULL)
+ ? va_arg(arglist, long double)
+ : (long double)(*((long double *)argarray[num]));
+ else
+ {
+ if (argarray == NULL)
+ parameters[i].data.longdoubleNumber = (long double)va_arg(arglist, double);
+ else
+ {
+ if (parameters[i].flags & FLAGS_SHORT)
+ parameters[i].data.longdoubleNumber = (long double)(*((float *)argarray[num]));
+ else
+ parameters[i].data.longdoubleNumber = (long double)(long double)(*((double *)argarray[num]));
+ }
+ }
+ }
+ break;
+
+#if defined(FORMAT_ERRNO)
+ case FORMAT_ERRNO:
+ parameters[i].data.errorNumber = errno;
+ break;
+#endif
+
+ default:
+ break;
+ }
+ } /* for all specifiers */
+ return num;
+}
+
+
+/*************************************************************************
+ *
+ * @FORMATTING
+ *
+ ************************************************************************/
+
+
+/*************************************************************************
+ * TrioWriteNumber [private]
+ *
+ * Description:
+ * Output a number.
+ * The complexity of this function is a result of the complexity
+ * of the dependencies of the flags.
+ */
+static void
+TrioWriteNumber(trio_T *self,
+ trio_uintmax_t number,
+ unsigned long flags,
+ int width,
+ int precision,
+ int base)
+{
+ BOOLEAN_T isNegative;
+ char buffer[MAX_CHARS_IN(trio_uintmax_t) * (1 + MAX_LOCALE_SEPARATOR_LENGTH) + 1];
+ char *bufferend;
+ char *pointer;
+ const char *digits;
+ int i;
+ int length;
+ char *p;
+ int charsPerThousand;
+ int groupingIndex;
+ int count;
+
+ assert(VALID(self));
+ assert(VALID(self->OutStream));
+ assert((base >= MIN_BASE && base <= MAX_BASE) || (base == NO_BASE));
+
+ digits = (flags & FLAGS_UPPER) ? internalDigitsUpper : internalDigitsLower;
+
+ isNegative = (flags & FLAGS_UNSIGNED)
+ ? FALSE
+ : ((trio_intmax_t)number < 0);
+ if (isNegative)
+ number = -number;
+
+ if (flags & FLAGS_QUAD)
+ number &= (trio_ulonglong_t)-1;
+ else if (flags & FLAGS_LONG)
+ number &= (unsigned long)-1;
+ else
+ number &= (unsigned int)-1;
+
+ /* Build number */
+ pointer = bufferend = &buffer[sizeof(buffer) - 1];
+ *pointer-- = NIL;
+ charsPerThousand = (int)internalGrouping[0];
+ groupingIndex = 1;
+ for (i = 1; i < (int)sizeof(buffer); i++)
+ {
+ *pointer-- = digits[number % base];
+ number /= base;
+ if (number == 0)
+ break;
+
+ if ((flags & FLAGS_QUOTE)
+ && (charsPerThousand != NO_GROUPING)
+ && (i % charsPerThousand == 0))
+ {
+ /*
+ * We are building the number from the least significant
+ * to the most significant digit, so we have to copy the
+ * thousand separator backwards
+ */
+ length = StrLength(internalThousandSeparator);
+ if (((int)(pointer - buffer) - length) > 0)
+ {
+ p = &internalThousandSeparator[length - 1];
+ while (length-- > 0)
+ *pointer-- = *p--;
+ }
+
+ /* Advance to next grouping number */
+ switch (internalGrouping[groupingIndex])
+ {
+ case CHAR_MAX: /* Disable grouping */
+ charsPerThousand = NO_GROUPING;
+ break;
+ case 0: /* Repeat last group */
+ break;
+ default:
+ charsPerThousand = (int)internalGrouping[groupingIndex++];
+ break;
+ }
+ }
+ }
+
+ /* Adjust width */
+ width -= (bufferend - pointer) - 1;
+
+ /* Adjust precision */
+ if (NO_PRECISION != precision)
+ {
+ precision -= (bufferend - pointer) - 1;
+ if (precision < 0)
+ precision = 0;
+ flags |= FLAGS_NILPADDING;
+ }
+
+ /* Adjust width further */
+ if (isNegative || (flags & FLAGS_SHOWSIGN) || (flags & FLAGS_SPACE))
+ width--;
+ if (flags & FLAGS_ALTERNATIVE)
+ {
+ switch (base)
+ {
+ case BASE_BINARY:
+ case BASE_HEX:
+ width -= 2;
+ break;
+ case BASE_OCTAL:
+ width--;
+ break;
+ default:
+ break;
+ }
+ }
+
+ /* Output prefixes spaces if needed */
+ if (! ((flags & FLAGS_LEFTADJUST) ||
+ ((flags & FLAGS_NILPADDING) && (precision == NO_PRECISION))))
+ {
+ count = (precision == NO_PRECISION) ? 0 : precision;
+ while (width-- > count)
+ self->OutStream(self, CHAR_ADJUST);
+ }
+
+ /* width has been adjusted for signs and alternatives */
+ if (isNegative)
+ self->OutStream(self, '-');
+ else if (flags & FLAGS_SHOWSIGN)
+ self->OutStream(self, '+');
+ else if (flags & FLAGS_SPACE)
+ self->OutStream(self, ' ');
+
+ if (flags & FLAGS_ALTERNATIVE)
+ {
+ switch (base)
+ {
+ case BASE_BINARY:
+ self->OutStream(self, '0');
+ self->OutStream(self, (flags & FLAGS_UPPER) ? 'B' : 'b');
+ break;
+
+ case BASE_OCTAL:
+ self->OutStream(self, '0');
+ break;
+
+ case BASE_HEX:
+ self->OutStream(self, '0');
+ self->OutStream(self, (flags & FLAGS_UPPER) ? 'X' : 'x');
+ break;
+
+ default:
+ break;
+ } /* switch base */
+ }
+
+ /* Output prefixed zero padding if needed */
+ if (flags & FLAGS_NILPADDING)
+ {
+ if (precision == NO_PRECISION)
+ precision = width;
+ while (precision-- > 0)
+ {
+ self->OutStream(self, '0');
+ width--;
+ }
+ }
+
+ /* Output the number itself */
+ while (*(++pointer))
+ {
+ self->OutStream(self, *pointer);
+ }
+
+ /* Output trailing spaces if needed */
+ if (flags & FLAGS_LEFTADJUST)
+ {
+ while (width-- > 0)
+ self->OutStream(self, CHAR_ADJUST);
+ }
+}
+
+/*************************************************************************
+ * TrioWriteStringCharacter [private]
+ *
+ * Description:
+ * Output a single character of a string
+ */
+static void
+TrioWriteStringCharacter(trio_T *self,
+ int ch,
+ unsigned long flags)
+{
+ if (flags & FLAGS_ALTERNATIVE)
+ {
+ if (! (isprint(ch) || isspace(ch)))
+ {
+ /*
+ * Non-printable characters are converted to C escapes or
+ * \number, if no C escape exists.
+ */
+ self->OutStream(self, CHAR_BACKSLASH);
+ switch (ch)
+ {
+ case '\007': self->OutStream(self, 'a'); break;
+ case '\b': self->OutStream(self, 'b'); break;
+ case '\f': self->OutStream(self, 'f'); break;
+ case '\n': self->OutStream(self, 'n'); break;
+ case '\r': self->OutStream(self, 'r'); break;
+ case '\t': self->OutStream(self, 't'); break;
+ case '\v': self->OutStream(self, 'v'); break;
+ case '\\': self->OutStream(self, '\\'); break;
+ default:
+ self->OutStream(self, 'x');
+ TrioWriteNumber(self, (trio_intmax_t)ch,
+ FLAGS_UNSIGNED | FLAGS_NILPADDING,
+ 2, 2, BASE_HEX);
+ break;
+ }
+ }
+ else if (ch == CHAR_BACKSLASH)
+ {
+ self->OutStream(self, CHAR_BACKSLASH);
+ self->OutStream(self, CHAR_BACKSLASH);
+ }
+ else
+ {
+ self->OutStream(self, ch);
+ }
+ }
+ else
+ {
+ self->OutStream(self, ch);
+ }
+}
+
+/*************************************************************************
+ * TrioWriteString [private]
+ *
+ * Description:
+ * Output a string
+ */
+static void
+TrioWriteString(trio_T *self,
+ const char *string,
+ unsigned long flags,
+ int width,
+ int precision)
+{
+ int length;
+ int ch;
+
+ assert(VALID(self));
+ assert(VALID(self->OutStream));
+
+ if (string == NULL)
+ {
+ string = null;
+ length = sizeof(null) - 1;
+ /* Disable quoting for the null pointer */
+ flags &= (~FLAGS_QUOTE);
+ width = 0;
+ }
+ else
+ {
+ length = StrLength(string);
+ }
+ if ((NO_PRECISION != precision) &&
+ (precision < length))
+ {
+ length = precision;
+ }
+ width -= length;
+
+ if (flags & FLAGS_QUOTE)
+ self->OutStream(self, CHAR_QUOTE);
+
+ if (! (flags & FLAGS_LEFTADJUST))
+ {
+ while (width-- > 0)
+ self->OutStream(self, CHAR_ADJUST);
+ }
+
+ while (length-- > 0)
+ {
+ /* The ctype parameters must be an unsigned char (or EOF) */
+ ch = (int)((unsigned char)(*string++));
+ TrioWriteStringCharacter(self, ch, flags);
+ }
+
+ if (flags & FLAGS_LEFTADJUST)
+ {
+ while (width-- > 0)
+ self->OutStream(self, CHAR_ADJUST);
+ }
+ if (flags & FLAGS_QUOTE)
+ self->OutStream(self, CHAR_QUOTE);
+}
+
+/*************************************************************************
+ * TrioWriteWideStringCharacter [private]
+ *
+ * Description:
+ * Output a wide string as a multi-byte sequence
+ */
+#if TRIO_WIDECHAR
+static int
+TrioWriteWideStringCharacter(trio_T *self,
+ wchar_t wch,
+ unsigned long flags,
+ int width)
+{
+ int size;
+ int i;
+ int ch;
+ char *string;
+ char buffer[MB_LEN_MAX + 1];
+
+ if (width == NO_WIDTH)
+ width = sizeof(buffer);
+
+ size = wctomb(buffer, wch);
+ if ((size <= 0) || (size > width) || (buffer[0] == NIL))
+ return 0;
+
+ string = buffer;
+ i = size;
+ while ((width >= i) && (width-- > 0) && (i-- > 0))
+ {
+ /* The ctype parameters must be an unsigned char (or EOF) */
+ ch = (int)((unsigned char)(*string++));
+ TrioWriteStringCharacter(self, ch, flags);
+ }
+ return size;
+}
+#endif /* TRIO_WIDECHAR */
+
+/*************************************************************************
+ * TrioWriteString [private]
+ *
+ * Description:
+ * Output a wide character string as a multi-byte string
+ */
+#if TRIO_WIDECHAR
+static void
+TrioWriteWideString(trio_T *self,
+ const wchar_t *wstring,
+ unsigned long flags,
+ int width,
+ int precision)
+{
+ int length;
+ int size;
+
+ assert(VALID(self));
+ assert(VALID(self->OutStream));
+
+#if defined(TRIO_COMPILER_SUPPORTS_MULTIBYTE)
+ mblen(NULL, 0);
+#endif
+
+ if (wstring == NULL)
+ {
+ TrioWriteString(self, NULL, flags, width, precision);
+ return;
+ }
+
+ if (NO_PRECISION == precision)
+ {
+ length = INT_MAX;
+ }
+ else
+ {
+ length = precision;
+ width -= length;
+ }
+
+ if (flags & FLAGS_QUOTE)
+ self->OutStream(self, CHAR_QUOTE);
+
+ if (! (flags & FLAGS_LEFTADJUST))
+ {
+ while (width-- > 0)
+ self->OutStream(self, CHAR_ADJUST);
+ }
+
+ while (length > 0)
+ {
+ size = TrioWriteWideStringCharacter(self, *wstring++, flags, length);
+ if (size == 0)
+ break; /* while */
+ length -= size;
+ }
+
+ if (flags & FLAGS_LEFTADJUST)
+ {
+ while (width-- > 0)
+ self->OutStream(self, CHAR_ADJUST);
+ }
+ if (flags & FLAGS_QUOTE)
+ self->OutStream(self, CHAR_QUOTE);
+}
+#endif /* TRIO_WIDECHAR */
+
+/*************************************************************************
+ * TrioWriteDouble [private]
+ */
+static void
+TrioWriteDouble(trio_T *self,
+ long double longdoubleNumber,
+ unsigned long flags,
+ int width,
+ int precision,
+ int base)
+{
+ int charsPerThousand;
+ int length;
+ double number;
+ double workNumber;
+ int integerDigits;
+ int fractionDigits;
+ int exponentDigits;
+ int expectedWidth;
+ int exponent;
+ unsigned int uExponent = 0;
+ double dblBase;
+ BOOLEAN_T isNegative;
+ BOOLEAN_T isExponentNegative = FALSE;
+ BOOLEAN_T isHex;
+ const char *digits;
+ char numberBuffer[MAX_MANTISSA_DIGITS
+ * (1 + MAX_LOCALE_SEPARATOR_LENGTH) + 1];
+ char *numberPointer;
+ char exponentBuffer[MAX_EXPONENT_DIGITS + 1];
+ char *exponentPointer = NULL;
+ int groupingIndex;
+ char *work;
+ int i;
+ BOOLEAN_T onlyzero;
+ int zeroes = 0;
+
+ assert(VALID(self));
+ assert(VALID(self->OutStream));
+ assert(base == BASE_DECIMAL || base == BASE_HEX);
+
+ number = (double)longdoubleNumber;
+
+ /* Look for infinite numbers and non-a-number first */
+ switch (TrioIsInfinite(number))
+ {
+ case 1:
+ /* Positive infinity */
+ TrioWriteString(self,
+ (flags & FLAGS_UPPER)
+ ? INFINITE_UPPER
+ : INFINITE_LOWER,
+ flags, width, precision);
+ return;
+
+ case -1:
+ /* Negative infinity */
+ TrioWriteString(self,
+ (flags & FLAGS_UPPER)
+ ? "-" INFINITE_UPPER
+ : "-" INFINITE_LOWER,
+ flags, width, precision);
+ return;
+
+ default:
+ /* Finitude */
+ break;
+ }
+ if (TrioIsNan(number))
+ {
+ TrioWriteString(self,
+ (flags & FLAGS_UPPER)
+ ? NAN_UPPER
+ : NAN_LOWER,
+ flags, width, precision);
+ return;
+ }
+
+ /* Normal numbers */
+ digits = (flags & FLAGS_UPPER) ? internalDigitsUpper : internalDigitsLower;
+ isHex = (base == BASE_HEX);
+ dblBase = (double)base;
+
+ if (precision == NO_PRECISION)
+ precision = FLT_DIG;
+
+ isNegative = (number < 0.0);
+ if (isNegative)
+ number = -number;
+
+ if ((flags & FLAGS_FLOAT_G) || isHex)
+ {
+ if (precision == 0)
+ precision = 1;
+
+ if ((number < 1.0e-4) || (number > pow(10.0, (double)precision)))
+ {
+ /* Use scientific notation */
+ flags |= FLAGS_FLOAT_E;
+ }
+ else if (number < 1.0)
+ {
+ /*
+ * Use normal notation. If the integer part of the number is
+ * zero, then adjust the precision to include leading fractional
+ * zeros.
+ */
+ workNumber = fabs(guarded_log10(number));
+ if (workNumber - floor(workNumber) < 0.001)
+ workNumber--;
+ zeroes = (int)floor(workNumber);
+ }
+ }
+
+ if (flags & FLAGS_FLOAT_E)
+ {
+ /* Scale the number */
+ workNumber = guarded_log10(number);
+ if (workNumber == -HUGE_VAL)
+ {
+ exponent = 0;
+ /* Undo setting */
+ if (flags & FLAGS_FLOAT_G)
+ flags &= ~FLAGS_FLOAT_E;
+ }
+ else
+ {
+ exponent = (int)floor(workNumber);
+ number /= pow(10.0, (double)exponent);
+ isExponentNegative = (exponent < 0);
+ uExponent = (isExponentNegative) ? -exponent : exponent;
+ /* No thousand separators */
+ flags &= ~FLAGS_QUOTE;
+ }
+ }
+
+ /*
+ * Truncated number.
+ *
+ * precision is number of significant digits for FLOAT_G
+ * and number of fractional digits for others
+ */
+ integerDigits = (floor(number) > DBL_EPSILON)
+ ? 1 + (int)guarded_log10(floor(number))
+ : 1;
+ fractionDigits = ((flags & FLAGS_FLOAT_G) && (zeroes == 0))
+ ? precision - integerDigits
+ : zeroes + precision;
+
+ number = floor(0.5 + number * pow(dblBase, (double)fractionDigits));
+ workNumber = (isHex
+ ? guarded_log16(0.5 + number)
+ : guarded_log10(0.5 + number));
+ if ((int)workNumber + 1 > integerDigits + fractionDigits)
+ {
+ if (flags & FLAGS_FLOAT_E)
+ {
+ /* Adjust if number was rounded up one digit (ie. 0.99 to 1.00) */
+ exponent--;
+ uExponent -= (isExponentNegative) ? 1 : -1;
+ number /= dblBase;
+ }
+ else
+ {
+ /* Adjust if number was rounded up one digit (ie. 99 to 100) */
+ integerDigits++;
+ }
+ }
+
+ /* Build the fraction part */
+ numberPointer = &numberBuffer[sizeof(numberBuffer) - 1];
+ *numberPointer = NIL;
+ onlyzero = TRUE;
+ for (i = 0; i < fractionDigits; i++)
+ {
+ *(--numberPointer) = digits[(int)fmod(number, dblBase)];
+ number = floor(number / dblBase);
+
+ if ((flags & FLAGS_FLOAT_G) && !(flags & FLAGS_ALTERNATIVE))
+ {
+ /* Prune trailing zeroes */
+ if (numberPointer[0] != digits[0])
+ onlyzero = FALSE;
+ else if (onlyzero && (numberPointer[0] == digits[0]))
+ numberPointer++;
+ }
+ else
+ onlyzero = FALSE;
+ }
+
+ /* Insert decimal point */
+ if ((flags & FLAGS_ALTERNATIVE) || ((fractionDigits > 0) && !onlyzero))
+ {
+ i = StrLength(internalDecimalPoint);
+ while (i> 0)
+ {
+ *(--numberPointer) = internalDecimalPoint[--i];
+ }
+ }
+ /* Insert the integer part and thousand separators */
+ charsPerThousand = (int)internalGrouping[0];
+ groupingIndex = 1;
+ for (i = 1; i < integerDigits + 1; i++)
+ {
+ *(--numberPointer) = digits[(int)fmod(number, dblBase)];
+ number = floor(number / dblBase);
+ if (number < DBL_EPSILON)
+ break;
+
+ if ((i > 0)
+ && ((flags & (FLAGS_FLOAT_E | FLAGS_QUOTE)) == FLAGS_QUOTE)
+ && (charsPerThousand != NO_GROUPING)
+ && (i % charsPerThousand == 0))
+ {
+ /*
+ * We are building the number from the least significant
+ * to the most significant digit, so we have to copy the
+ * thousand separator backwards
+ */
+ length = StrLength(internalThousandSeparator);
+ integerDigits += length;
+ if (((int)(numberPointer - numberBuffer) - length) > 0)
+ {
+ work = &internalThousandSeparator[length - 1];
+ while (length-- > 0)
+ *(--numberPointer) = *work--;
+ }
+
+ /* Advance to next grouping number */
+ if (charsPerThousand != NO_GROUPING)
+ {
+ switch (internalGrouping[groupingIndex])
+ {
+ case CHAR_MAX: /* Disable grouping */
+ charsPerThousand = NO_GROUPING;
+ break;
+ case 0: /* Repeat last group */
+ break;
+ default:
+ charsPerThousand = (int)internalGrouping[groupingIndex++];
+ break;
+ }
+ }
+ }
+ }
+
+ /* Build the exponent */
+ exponentDigits = 0;
+ if (flags & FLAGS_FLOAT_E)
+ {
+ exponentPointer = &exponentBuffer[sizeof(exponentBuffer) - 1];
+ *exponentPointer-- = NIL;
+ do {
+ *exponentPointer-- = digits[uExponent % base];
+ uExponent /= base;
+ exponentDigits++;
+ } while (uExponent);
+ }
+
+ /*
+ * Calculate expected width.
+ * sign + integer part + thousands separators + decimal point
+ * + fraction + exponent
+ */
+ expectedWidth = StrLength(numberPointer);
+ if (isNegative || (flags & FLAGS_SHOWSIGN))
+ expectedWidth += sizeof("-") - 1;
+ if (exponentDigits > 0)
+ expectedWidth += exponentDigits +
+ ((exponentDigits > 1) ? sizeof("E+") : sizeof("E+0")) - 1;
+ if (isHex)
+ expectedWidth += sizeof("0X") - 1;
+
+ /* Output prefixing */
+ if (flags & FLAGS_NILPADDING)
+ {
+ /* Leading zeros must be after sign */
+ if (isNegative)
+ self->OutStream(self, '-');
+ else if (flags & FLAGS_SHOWSIGN)
+ self->OutStream(self, '+');
+ if (isHex)
+ {
+ self->OutStream(self, '0');
+ self->OutStream(self, (flags & FLAGS_UPPER) ? 'X' : 'x');
+ }
+ if (!(flags & FLAGS_LEFTADJUST))
+ {
+ for (i = expectedWidth; i < width; i++)
+ {
+ self->OutStream(self, '0');
+ }
+ }
+ }
+ else
+ {
+ /* Leading spaces must be before sign */
+ if (!(flags & FLAGS_LEFTADJUST))
+ {
+ for (i = expectedWidth; i < width; i++)
+ {
+ self->OutStream(self, CHAR_ADJUST);
+ }
+ }
+ if (isNegative)
+ self->OutStream(self, '-');
+ else if (flags & FLAGS_SHOWSIGN)
+ self->OutStream(self, '+');
+ if (isHex)
+ {
+ self->OutStream(self, '0');
+ self->OutStream(self, (flags & FLAGS_UPPER) ? 'X' : 'x');
+ }
+ }
+ /* Output number */
+ for (i = 0; numberPointer[i]; i++)
+ {
+ self->OutStream(self, numberPointer[i]);
+ }
+ /* Output exponent */
+ if (exponentDigits > 0)
+ {
+ self->OutStream(self,
+ isHex
+ ? ((flags & FLAGS_UPPER) ? 'P' : 'p')
+ : ((flags & FLAGS_UPPER) ? 'E' : 'e'));
+ self->OutStream(self, (isExponentNegative) ? '-' : '+');
+
+ /* The exponent must contain at least two digits */
+ if (exponentDigits == 1)
+ self->OutStream(self, '0');
+
+ for (i = 0; i < exponentDigits; i++)
+ {
+ self->OutStream(self, exponentPointer[i + 1]);
+ }
+ }
+ /* Output trailing spaces */
+ if (flags & FLAGS_LEFTADJUST)
+ {
+ for (i = expectedWidth; i < width; i++)
+ {
+ self->OutStream(self, CHAR_ADJUST);
+ }
+ }
+}
+
+/*************************************************************************
+ * TrioFormatProcess [private]
+ */
+static int
+TrioFormatProcess(trio_T *data,
+ const char *format,
+ parameter_T *parameters)
+
+{
+#if defined(TRIO_COMPILER_SUPPORTS_MULTIBYTE)
+ int charlen;
+#endif
+ int i;
+ const char *string;
+ void *pointer;
+ unsigned long flags;
+ int width;
+ int precision;
+ int base;
+ int index;
+
+ index = 0;
+ i = 0;
+#if defined(TRIO_COMPILER_SUPPORTS_MULTIBYTE)
+ mblen(NULL, 0);
+#endif
+
+ while (format[index])
+ {
+#if defined(TRIO_COMPILER_SUPPORTS_MULTIBYTE)
+ if (! isascii(format[index]))
+ {
+ charlen = mblen(&format[index], MB_LEN_MAX);
+ while (charlen-- > 0)
+ {
+ data->OutStream(data, format[index++]);
+ }
+ continue; /* while */
+ }
+#endif /* TRIO_COMPILER_SUPPORTS_MULTIBYTE */
+ if (CHAR_IDENTIFIER == format[index])
+ {
+ if (CHAR_IDENTIFIER == format[index + 1])
+ {
+ data->OutStream(data, CHAR_IDENTIFIER);
+ index += 2;
+ }
+ else
+ {
+ /* Skip the parameter entries */
+ while (parameters[i].type == FORMAT_PARAMETER)
+ i++;
+
+ flags = parameters[i].flags;
+
+ /* Find width */
+ width = parameters[i].width;
+ if (flags & FLAGS_WIDTH_PARAMETER)
+ {
+ /* Get width from parameter list */
+ width = (int)parameters[width].data.number.as_signed;
+ }
+
+ /* Find precision */
+ if (flags & FLAGS_PRECISION)
+ {
+ precision = parameters[i].precision;
+ if (flags & FLAGS_PRECISION_PARAMETER)
+ {
+ /* Get precision from parameter list */
+ precision = (int)parameters[precision].data.number.as_signed;
+ }
+ }
+ else
+ {
+ precision = NO_PRECISION;
+ }
+
+ /* Find base */
+ base = parameters[i].base;
+ if (flags & FLAGS_BASE_PARAMETER)
+ {
+ /* Get base from parameter list */
+ base = (int)parameters[base].data.number.as_signed;
+ }
+
+ switch (parameters[i].type)
+ {
+ case FORMAT_CHAR:
+ if (flags & FLAGS_QUOTE)
+ data->OutStream(data, CHAR_QUOTE);
+ if (! (flags & FLAGS_LEFTADJUST))
+ {
+ while (--width > 0)
+ data->OutStream(data, CHAR_ADJUST);
+ }
+#if TRIO_WIDECHAR
+ if (flags & FLAGS_WIDECHAR)
+ {
+ TrioWriteWideStringCharacter(data,
+ (wchar_t)parameters[i].data.number.as_signed,
+ flags,
+ NO_WIDTH);
+ }
+ else
+#endif
+ TrioWriteStringCharacter(data,
+ (int)parameters[i].data.number.as_signed,
+ flags);
+
+ if (flags & FLAGS_LEFTADJUST)
+ {
+ while(--width > 0)
+ data->OutStream(data, CHAR_ADJUST);
+ }
+ if (flags & FLAGS_QUOTE)
+ data->OutStream(data, CHAR_QUOTE);
+
+ break; /* FORMAT_CHAR */
+
+ case FORMAT_INT:
+ if (base == NO_BASE)
+ base = BASE_DECIMAL;
+
+ TrioWriteNumber(data,
+ parameters[i].data.number.as_signed,
+ flags,
+ width,
+ precision,
+ base);
+
+ break; /* FORMAT_INT */
+
+ case FORMAT_DOUBLE:
+ TrioWriteDouble(data,
+ parameters[i].data.longdoubleNumber,
+ flags,
+ width,
+ precision,
+ base);
+ break; /* FORMAT_DOUBLE */
+
+ case FORMAT_STRING:
+#if TRIO_WIDECHAR
+ if (flags & FLAGS_WIDECHAR)
+ {
+ TrioWriteWideString(data,
+ parameters[i].data.wstring,
+ flags,
+ width,
+ precision);
+ }
+ else
+#endif
+#ifdef QUALIFIER_ESCAPE
+ {
+ char *s = NULL;
+ static const char* empty = "(null)";
+ switch (parameters[i].escape)
+ {
+ case ESCAPE_ULM:
+ s = edg_wll_LogEscape(parameters[i].data.string);
+ break;
+ case ESCAPE_XML:
+ s = edg_wll_EscapeXML(parameters[i].data.string);
+ break;
+ case ESCAPE_SQL:
+ s = edg_wll_EscapeSQL(parameters[i].data.string);
+ break;
+ case ESCAPE_NONE:
+ s = strdup(parameters[i].data.string ? parameters[i].data.string : empty);
+ break;
+ }
+ TrioWriteString(data,s,flags,width,precision);
+ free(s);
+ }
+#else
+ {
+ TrioWriteString(data,
+ parameters[i].data.string,
+ flags,
+ width,
+ precision);
+ }
+#endif
+ break; /* FORMAT_STRING */
+
+ case FORMAT_POINTER:
+ {
+ reference_T reference;
+
+ reference.data = data;
+ reference.parameter = ¶meters[i];
+ trio_print_pointer(&reference, parameters[i].data.pointer);
+ }
+ break; /* FORMAT_POINTER */
+
+ case FORMAT_COUNT:
+ pointer = parameters[i].data.pointer;
+ if (NULL != pointer)
+ {
+ /*
+ * C99 paragraph 7.19.6.1.8 says "the number of
+ * characters written to the output stream so far by
+ * this call", which is data->committed
+ */
+#if defined(QUALIFIER_SIZE_T) || defined(QUALIFIER_SIZE_T_UPPER)
+ if (flags & FLAGS_SIZE_T)
+ *(size_t *)pointer = (size_t)data->committed;
+ else
+#endif
+#if defined(QUALIFIER_PTRDIFF_T)
+ if (flags & FLAGS_PTRDIFF_T)
+ *(ptrdiff_t *)pointer = (ptrdiff_t)data->committed;
+ else
+#endif
+#if defined(QUALIFIER_INTMAX_T)
+ if (flags & FLAGS_INTMAX_T)
+ *(trio_intmax_t *)pointer = (trio_intmax_t)data->committed;
+ else
+#endif
+ if (flags & FLAGS_QUAD)
+ {
+ *(trio_ulonglong_t *)pointer = (trio_ulonglong_t)data->committed;
+ }
+ else if (flags & FLAGS_LONG)
+ {
+ *(long int *)pointer = (long int)data->committed;
+ }
+ else if (flags & FLAGS_SHORT)
+ {
+ *(short int *)pointer = (short int)data->committed;
+ }
+ else
+ {
+ *(int *)pointer = (int)data->committed;
+ }
+ }
+ break; /* FORMAT_COUNT */
+
+ case FORMAT_PARAMETER:
+ break; /* FORMAT_PARAMETER */
+
+#if defined(FORMAT_ERRNO)
+ case FORMAT_ERRNO:
+ string = StrError(parameters[i].data.errorNumber);
+ if (string)
+ {
+ TrioWriteString(data,
+ string,
+ flags,
+ width,
+ precision);
+ }
+ else
+ {
+ data->OutStream(data, '#');
+ TrioWriteNumber(data,
+ (trio_intmax_t)parameters[i].data.errorNumber,
+ flags,
+ width,
+ precision,
+ BASE_DECIMAL);
+ }
+ break; /* FORMAT_ERRNO */
+#endif /* defined(FORMAT_ERRNO) */
+
+#if defined(FORMAT_USER_DEFINED)
+ case FORMAT_USER_DEFINED:
+ {
+ reference_T reference;
+ userdef_T *def = NULL;
+
+ if (parameters[i].user_name[0] == NIL)
+ {
+ /* Use handle */
+ if ((i > 0) ||
+ (parameters[i - 1].type == FORMAT_PARAMETER))
+ def = (userdef_T *)parameters[i - 1].data.pointer;
+ }
+ else
+ {
+ /* Look up namespace */
+ def = TrioFindNamespace(parameters[i].user_name, NULL);
+ }
+ if (def) {
+ reference.data = data;
+ reference.parameter = ¶meters[i];
+ def->callback(&reference);
+ }
+ }
+ break;
+#endif /* defined(FORMAT_USER_DEFINED) */
+
+ default:
+ break;
+ } /* switch parameter type */
+
+ /* Prepare for next */
+ index = parameters[i].indexAfterSpecifier;
+ i++;
+ }
+ }
+ else /* not identifier */
+ {
+ data->OutStream(data, format[index++]);
+ }
+ }
+ return data->processed;
+}
+
+/*************************************************************************
+ * TrioFormatRef [private]
+ */
+static int
+TrioFormatRef(reference_T *reference,
+ const char *format,
+ va_list arglist,
+ void **argarray)
+{
+ int status;
+ parameter_T parameters[MAX_PARAMETERS];
+
+ status = TrioPreprocess(TYPE_PRINT, format, parameters, arglist, argarray);
+ if (status < 0)
+ return status;
+
+ return TrioFormatProcess(reference->data, format, parameters);
+}
+
+/*************************************************************************
+ * TrioFormat [private]
+ *
+ * Description:
+ * This is the main engine for formatting output
+ */
+static int
+TrioFormat(void *destination,
+ size_t destinationSize,
+ void (*OutStream)(trio_T *, int),
+ const char *format,
+ va_list arglist,
+ void **argarray)
+{
+ int status;
+ trio_T data;
+ parameter_T parameters[MAX_PARAMETERS];
+
+ assert(VALID(OutStream));
+ assert(VALID(format));
+
+ memset(&data, 0, sizeof(data));
+ data.OutStream = OutStream;
+ data.location = destination;
+ data.max = destinationSize;
+
+#if defined(USE_LOCALE)
+ if (NULL == internalLocaleValues)
+ {
+ TrioSetLocale();
+ }
+#endif
+
+ status = TrioPreprocess(TYPE_PRINT, format, parameters, arglist, argarray);
+ if (status < 0)
+ return status;
+
+ return TrioFormatProcess(&data, format, parameters);
+}
+
+/*************************************************************************
+ * TrioOutStreamFile [private]
+ */
+static void
+TrioOutStreamFile(trio_T *self,
+ int output)
+{
+ FILE *file = (FILE *)self->location;
+
+ assert(VALID(self));
+ assert(VALID(file));
+
+ self->processed++;
+ self->committed++;
+ (void)fputc(output, file);
+}
+
+/*************************************************************************
+ * TrioOutStreamFileDescriptor [private]
+ */
+static void
+TrioOutStreamFileDescriptor(trio_T *self,
+ int output)
+{
+ int fd = *((int *)self->location);
+ char ch;
+
+ assert(VALID(self));
+
+ ch = (char)output;
+ (void)write(fd, &ch, sizeof(char));
+ self->processed++;
+ self->committed++;
+}
+
+/*************************************************************************
+ * TrioOutStreamString [private]
+ */
+static void
+TrioOutStreamString(trio_T *self,
+ int output)
+{
+ char **buffer = (char **)self->location;
+
+ assert(VALID(self));
+ assert(VALID(buffer));
+
+ **buffer = (char)output;
+ (*buffer)++;
+ self->processed++;
+ self->committed++;
+}
+
+/*************************************************************************
+ * TrioOutStreamStringMax [private]
+ */
+static void
+TrioOutStreamStringMax(trio_T *self,
+ int output)
+{
+ char **buffer;
+
+ assert(VALID(self));
+ buffer = (char **)self->location;
+ assert(VALID(buffer));
+
+ if (self->processed < self->max)
+ {
+ **buffer = (char)output;
+ (*buffer)++;
+ self->committed++;
+ }
+ self->processed++;
+}
+
+/*************************************************************************
+ * TrioOutStreamStringDynamic [private]
+ */
+#define DYNAMIC_START_SIZE 32
+struct dynamicBuffer {
+ char *buffer;
+ size_t length;
+ size_t allocated;
+};
+
+static void
+TrioOutStreamStringDynamic(trio_T *self,
+ int output)
+{
+ struct dynamicBuffer *infop;
+
+ assert(VALID(self));
+ assert(VALID(self->location));
+
+ infop = (struct dynamicBuffer *)self->location;
+
+ if (infop->buffer == NULL)
+ {
+ /* Start with a reasonable size */
+ infop->buffer = (char *)TRIO_MALLOC(DYNAMIC_START_SIZE);
+ if (infop->buffer == NULL)
+ return; /* fail */
+
+ infop->allocated = DYNAMIC_START_SIZE;
+ self->processed = 0;
+ self->committed = 0;
+ }
+ else if (self->committed + sizeof(NIL) >= infop->allocated)
+ {
+ char *newptr;
+
+ /* Allocate increasing chunks */
+ newptr = (char *)TRIO_REALLOC(infop->buffer, infop->allocated * 2);
+
+ if (newptr == NULL)
+ return;
+
+ infop->buffer = newptr;
+ infop->allocated *= 2;
+ }
+
+ infop->buffer[self->committed] = (char)output;
+ self->committed++;
+ self->processed++;
+
+ infop->length = self->committed;
+}
+
+/*************************************************************************
+ * printf
+ */
+int
+trio_printf(const char *format,
+ ...)
+{
+ int status;
+ va_list args;
+
+ assert(VALID(format));
+
+ va_start(args, format);
+ status = TrioFormat(stdout, 0, TrioOutStreamFile, format, args, NULL);
+ va_end(args);
+ return status;
+}
+
+int
+trio_vprintf(const char *format,
+ va_list args)
+{
+ assert(VALID(format));
+
+ return TrioFormat(stdout, 0, TrioOutStreamFile, format, args, NULL);
+}
+
+#ifdef __GNUC__
+#define UNUSED_VAR __attribute__((unused))
+#else
+#define UNUSED_VAR
+#endif
+
+static void shutup_unitialized(va_list *dummy UNUSED_VAR) {
+}
+
+int
+trio_printfv(const char *format,
+ void ** args)
+{
+ va_list dummy;
+ shutup_unitialized(&dummy);
+
+ assert(VALID(format));
+
+ return TrioFormat(stdout, 0, TrioOutStreamFile, format, dummy, args);
+}
+
+/*************************************************************************
+ * fprintf
+ */
+int
+trio_fprintf(FILE *file,
+ const char *format,
+ ...)
+{
+ int status;
+ va_list args;
+
+ assert(VALID(file));
+ assert(VALID(format));
+
+ va_start(args, format);
+ status = TrioFormat(file, 0, TrioOutStreamFile, format, args, NULL);
+ va_end(args);
+ return status;
+}
+
+int
+trio_vfprintf(FILE *file,
+ const char *format,
+ va_list args)
+{
+ assert(VALID(file));
+ assert(VALID(format));
+
+ return TrioFormat(file, 0, TrioOutStreamFile, format, args, NULL);
+}
+
+int
+trio_fprintfv(FILE *file,
+ const char *format,
+ void ** args)
+{
+ va_list dummy;
+ shutup_unitialized(&dummy);
+
+ assert(VALID(file));
+ assert(VALID(format));
+
+ return TrioFormat(file, 0, TrioOutStreamFile, format, dummy, args);
+}
+
+/*************************************************************************
+ * dprintf
+ */
+int
+trio_dprintf(int fd,
+ const char *format,
+ ...)
+{
+ int status;
+ va_list args;
+
+ assert(VALID(format));
+
+ va_start(args, format);
+ status = TrioFormat(&fd, 0, TrioOutStreamFileDescriptor, format, args, NULL);
+ va_end(args);
+ return status;
+}
+
+int
+trio_vdprintf(int fd,
+ const char *format,
+ va_list args)
+{
+ assert(VALID(format));
+
+ return TrioFormat(&fd, 0, TrioOutStreamFileDescriptor, format, args, NULL);
+}
+
+int
+trio_dprintfv(int fd,
+ const char *format,
+ void **args)
+{
+ va_list dummy;
+ shutup_unitialized(&dummy);
+
+ assert(VALID(format));
+
+ return TrioFormat(&fd, 0, TrioOutStreamFileDescriptor, format, dummy, args);
+}
+
+/*************************************************************************
+ * sprintf
+ */
+int
+trio_sprintf(char *buffer,
+ const char *format,
+ ...)
+{
+ int status;
+ va_list args;
+
+ assert(VALID(buffer));
+ assert(VALID(format));
+
+ va_start(args, format);
+ status = TrioFormat(&buffer, 0, TrioOutStreamString, format, args, NULL);
+ *buffer = NIL; /* Terminate with NIL character */
+ va_end(args);
+ return status;
+}
+
+int
+trio_vsprintf(char *buffer,
+ const char *format,
+ va_list args)
+{
+ int status;
+
+ assert(VALID(buffer));
+ assert(VALID(format));
+
+ status = TrioFormat(&buffer, 0, TrioOutStreamString, format, args, NULL);
+ *buffer = NIL;
+ return status;
+}
+
+int
+trio_sprintfv(char *buffer,
+ const char *format,
+ void **args)
+{
+ int status;
+ va_list dummy;
+ shutup_unitialized(&dummy);
+
+ assert(VALID(buffer));
+ assert(VALID(format));
+
+ status = TrioFormat(&buffer, 0, TrioOutStreamString, format, dummy, args);
+ *buffer = NIL;
+ return status;
+}
+
+/*************************************************************************
+ * snprintf
+ */
+int
+trio_snprintf(char *buffer,
+ size_t bufferSize,
+ const char *format,
+ ...)
+{
+ int status;
+ va_list args;
+
+ assert(VALID(buffer));
+ assert(VALID(format));
+
+ va_start(args, format);
+ status = TrioFormat(&buffer, bufferSize > 0 ? bufferSize - 1 : 0,
+ TrioOutStreamStringMax, format, args, NULL);
+ if (bufferSize > 0)
+ *buffer = NIL;
+ va_end(args);
+ return status;
+}
+
+int
+trio_vsnprintf(char *buffer,
+ size_t bufferSize,
+ const char *format,
+ va_list args)
+{
+ int status;
+
+ assert(VALID(buffer));
+ assert(VALID(format));
+
+ status = TrioFormat(&buffer, bufferSize > 0 ? bufferSize - 1 : 0,
+ TrioOutStreamStringMax, format, args, NULL);
+ if (bufferSize > 0)
+ *buffer = NIL;
+ return status;
+}
+
+int
+trio_snprintfv(char *buffer,
+ size_t bufferSize,
+ const char *format,
+ void **args)
+{
+ int status;
+ va_list dummy;
+ shutup_unitialized(&dummy);
+
+ assert(VALID(buffer));
+ assert(VALID(format));
+
+ status = TrioFormat(&buffer, bufferSize > 0 ? bufferSize - 1 : 0,
+ TrioOutStreamStringMax, format, dummy, args);
+ if (bufferSize > 0)
+ *buffer = NIL;
+ return status;
+}
+
+/*************************************************************************
+ * snprintfcat
+ * Appends the new string to the buffer string overwriting the '\0'
+ * character at the end of buffer.
+ */
+int
+trio_snprintfcat(char *buffer,
+ size_t bufferSize,
+ const char *format,
+ ...)
+{
+ int status;
+ va_list args;
+ size_t buf_len;
+
+ va_start(args, format);
+
+ assert(VALID(buffer));
+ assert(VALID(format));
+
+ buf_len = strlen(buffer);
+ buffer = &buffer[buf_len];
+
+ status = TrioFormat(&buffer, bufferSize - 1 - buf_len,
+ TrioOutStreamStringMax, format, args, NULL);
+ va_end(args);
+ *buffer = NIL;
+ return status;
+}
+
+int
+trio_vsnprintfcat(char *buffer,
+ size_t bufferSize,
+ const char *format,
+ va_list args)
+{
+ int status;
+ size_t buf_len;
+ assert(VALID(buffer));
+ assert(VALID(format));
+
+ buf_len = strlen(buffer);
+ buffer = &buffer[buf_len];
+ status = TrioFormat(&buffer, bufferSize - 1 - buf_len,
+ TrioOutStreamStringMax, format, args, NULL);
+ *buffer = NIL;
+ return status;
+}
+
+/*************************************************************************
+ * trio_aprintf
+ */
+
+/* Deprecated */
+char *
+trio_aprintf(const char *format,
+ ...)
+{
+ va_list args;
+ struct dynamicBuffer info;
+
+ assert(VALID(format));
+
+ info.buffer = NULL;
+ info.length = 0;
+ info.allocated = 0;
+
+ va_start(args, format);
+ (void)TrioFormat(&info, 0, TrioOutStreamStringDynamic, format, args, NULL);
+ va_end(args);
+ if (info.length) {
+ info.buffer[info.length] = NIL; /* we terminate this with a zero byte */
+ return info.buffer;
+ }
+ else
+ return NULL;
+}
+
+/* Deprecated */
+char *
+trio_vaprintf(const char *format,
+ va_list args)
+{
+ struct dynamicBuffer info;
+
+ assert(VALID(format));
+
+ info.buffer = NULL;
+ info.length = 0;
+ info.allocated = 0;
+
+ (void)TrioFormat(&info, 0, TrioOutStreamStringDynamic, format, args, NULL);
+ if (info.length) {
+ info.buffer[info.length] = NIL; /* we terminate this with a zero byte */
+ return info.buffer;
+ }
+ else
+ return NULL;
+}
+
+int
+trio_asprintf(char **result,
+ const char *format,
+ ...)
+{
+ va_list args;
+ int status;
+ struct dynamicBuffer info;
+
+ assert(VALID(format));
+
+ info.buffer = NULL;
+ info.length = 0;
+ info.allocated = 0;
+
+ va_start(args, format);
+ status = TrioFormat(&info, 0, TrioOutStreamStringDynamic, format, args, NULL);
+ va_end(args);
+ if (status < 0) {
+ *result = NULL;
+ return status;
+ }
+ if (info.length == 0) {
+ /*
+ * If the length is zero, no characters have been written and therefore
+ * no memory has been allocated, but we must to allocate and return an
+ * empty string.
+ */
+ info.buffer = (char *)TRIO_MALLOC(sizeof(char));
+ if (info.buffer == NULL) {
+ *result = NULL;
+ return TRIO_ERROR_RETURN(TRIO_ENOMEM, 0);
+ }
+ }
+ info.buffer[info.length] = NIL; /* we terminate this with a zero byte */
+ *result = info.buffer;
+
+ return status;
+}
+
+int
+trio_vasprintf(char **result,
+ const char *format,
+ va_list args)
+{
+ int status;
+ struct dynamicBuffer info;
+
+ assert(VALID(format));
+
+ info.buffer = NULL;
+ info.length = 0;
+ info.allocated = 0;
+
+ status = TrioFormat(&info, 0, TrioOutStreamStringDynamic, format, args, NULL);
+ if (status < 0) {
+ *result = NULL;
+ return status;
+ }
+ if (info.length == 0) {
+ info.buffer = (char *)TRIO_MALLOC(sizeof(char));
+ if (info.buffer == NULL) {
+ *result = NULL;
+ return TRIO_ERROR_RETURN(TRIO_ENOMEM, 0);
+ }
+ }
+ info.buffer[info.length] = NIL; /* we terminate this with a zero byte */
+ *result = info.buffer;
+
+ return status;
+}
+
+
+/*************************************************************************
+ *
+ * @CALLBACK
+ *
+ ************************************************************************/
+
+
+/*************************************************************************
+ * trio_register [public]
+ */
+void *
+trio_register(trio_callback_t callback,
+ const char *name)
+{
+ userdef_T *def;
+ userdef_T *prev = NULL;
+
+ if (callback == NULL)
+ return NULL;
+
+ if (name)
+ {
+ /* Handle built-in namespaces */
+ if (name[0] == ':')
+ {
+ if (StrEqual(name, ":enter"))
+ {
+ internalEnterCriticalRegion = callback;
+ }
+ else if (StrEqual(name, ":leave"))
+ {
+ internalLeaveCriticalRegion = callback;
+ }
+ return NULL;
+ }
+
+ /* Bail out if namespace is too long */
+ if (StrLength(name) >= MAX_USER_NAME)
+ return NULL;
+
+ /* Bail out if namespace already is registered */
+ def = TrioFindNamespace(name, &prev);
+ if (def)
+ return NULL;
+ }
+
+ def = (userdef_T *)TRIO_MALLOC(sizeof(userdef_T));
+ if (def)
+ {
+ if (internalEnterCriticalRegion)
+ (void)internalEnterCriticalRegion(NULL);
+
+ if (name)
+ {
+ /* Link into internal list */
+ if (prev == NULL)
+ internalUserDef = def;
+ else
+ prev->next = def;
+ }
+ /* Initialize */
+ def->callback = callback;
+ def->name = (name == NULL)
+ ? NULL
+ : StrDuplicate(name);
+ def->next = NULL;
+
+ if (internalLeaveCriticalRegion)
+ (void)internalLeaveCriticalRegion(NULL);
+ }
+ return def;
+}
+
+/*************************************************************************
+ * trio_unregister [public]
+ */
+void
+trio_unregister(void *handle)
+{
+ userdef_T *self = (userdef_T *)handle;
+ userdef_T *def;
+ userdef_T *prev = NULL;
+
+ assert(VALID(self));
+
+ if (self->name)
+ {
+ def = TrioFindNamespace(self->name, &prev);
+ if (def)
+ {
+ if (internalEnterCriticalRegion)
+ (void)internalEnterCriticalRegion(NULL);
+
+ if (prev == NULL)
+ internalUserDef = NULL;
+ else
+ prev->next = def->next;
+
+ if (internalLeaveCriticalRegion)
+ (void)internalLeaveCriticalRegion(NULL);
+ }
+ StrFree(self->name);
+ }
+ TRIO_FREE(self);
+}
+
+/*************************************************************************
+ * trio_get_format [public]
+ */
+const char *
+trio_get_format(void *ref)
+{
+ assert(((reference_T *)ref)->parameter->type == FORMAT_USER_DEFINED);
+
+ return (((reference_T *)ref)->parameter->user_data);
+}
+
+/*************************************************************************
+ * trio_get_argument [public]
+ */
+void *
+trio_get_argument(void *ref)
+{
+ assert(((reference_T *)ref)->parameter->type == FORMAT_USER_DEFINED);
+
+ return ((reference_T *)ref)->parameter->data.pointer;
+}
+
+/*************************************************************************
+ * trio_get_width / trio_set_width [public]
+ */
+int
+trio_get_width(void *ref)
+{
+ return ((reference_T *)ref)->parameter->width;
+}
+
+void
+trio_set_width(void *ref,
+ int width)
+{
+ ((reference_T *)ref)->parameter->width = width;
+}
+
+/*************************************************************************
+ * trio_get_precision / trio_set_precision [public]
+ */
+int
+trio_get_precision(void *ref)
+{
+ return (((reference_T *)ref)->parameter->precision);
+}
+
+void
+trio_set_precision(void *ref,
+ int precision)
+{
+ ((reference_T *)ref)->parameter->precision = precision;
+}
+
+/*************************************************************************
+ * trio_get_base / trio_set_base [public]
+ */
+int
+trio_get_base(void *ref)
+{
+ return (((reference_T *)ref)->parameter->base);
+}
+
+void
+trio_set_base(void *ref,
+ int base)
+{
+ ((reference_T *)ref)->parameter->base = base;
+}
+
+/*************************************************************************
+ * trio_get_long / trio_set_long [public]
+ */
+int
+trio_get_long(void *ref)
+{
+ return (((reference_T *)ref)->parameter->flags & FLAGS_LONG);
+}
+
+void
+trio_set_long(void *ref,
+ int is_long)
+{
+ if (is_long)
+ ((reference_T *)ref)->parameter->flags |= FLAGS_LONG;
+ else
+ ((reference_T *)ref)->parameter->flags &= ~FLAGS_LONG;
+}
+
+/*************************************************************************
+ * trio_get_longlong / trio_set_longlong [public]
+ */
+int
+trio_get_longlong(void *ref)
+{
+ return (((reference_T *)ref)->parameter->flags & FLAGS_QUAD);
+}
+
+void
+trio_set_longlong(void *ref,
+ int is_longlong)
+{
+ if (is_longlong)
+ ((reference_T *)ref)->parameter->flags |= FLAGS_QUAD;
+ else
+ ((reference_T *)ref)->parameter->flags &= ~FLAGS_QUAD;
+}
+
+/*************************************************************************
+ * trio_get_longdouble / trio_set_longdouble [public]
+ */
+int
+trio_get_longdouble(void *ref)
+{
+ return (((reference_T *)ref)->parameter->flags & FLAGS_LONGDOUBLE);
+}
+
+void
+trio_set_longdouble(void *ref,
+ int is_longdouble)
+{
+ if (is_longdouble)
+ ((reference_T *)ref)->parameter->flags |= FLAGS_LONGDOUBLE;
+ else
+ ((reference_T *)ref)->parameter->flags &= ~FLAGS_LONGDOUBLE;
+}
+
+/*************************************************************************
+ * trio_get_short / trio_set_short [public]
+ */
+int
+trio_get_short(void *ref)
+{
+ return (((reference_T *)ref)->parameter->flags & FLAGS_SHORT);
+}
+
+void
+trio_set_short(void *ref,
+ int is_short)
+{
+ if (is_short)
+ ((reference_T *)ref)->parameter->flags |= FLAGS_SHORT;
+ else
+ ((reference_T *)ref)->parameter->flags &= ~FLAGS_SHORT;
+}
+
+/*************************************************************************
+ * trio_get_shortshort / trio_set_shortshort [public]
+ */
+int
+trio_get_shortshort(void *ref)
+{
+ return (((reference_T *)ref)->parameter->flags & FLAGS_SHORTSHORT);
+}
+
+void
+trio_set_shortshort(void *ref,
+ int is_shortshort)
+{
+ if (is_shortshort)
+ ((reference_T *)ref)->parameter->flags |= FLAGS_SHORTSHORT;
+ else
+ ((reference_T *)ref)->parameter->flags &= ~FLAGS_SHORTSHORT;
+}
+
+/*************************************************************************
+ * trio_get_alternative / trio_set_alternative [public]
+ */
+int
+trio_get_alternative(void *ref)
+{
+ return (((reference_T *)ref)->parameter->flags & FLAGS_ALTERNATIVE);
+}
+
+void
+trio_set_alternative(void *ref,
+ int is_alternative)
+{
+ if (is_alternative)
+ ((reference_T *)ref)->parameter->flags |= FLAGS_ALTERNATIVE;
+ else
+ ((reference_T *)ref)->parameter->flags &= ~FLAGS_ALTERNATIVE;
+}
+
+/*************************************************************************
+ * trio_get_alignment / trio_set_alignment [public]
+ */
+int
+trio_get_alignment(void *ref)
+{
+ return (((reference_T *)ref)->parameter->flags & FLAGS_LEFTADJUST);
+}
+
+void
+trio_set_alignment(void *ref,
+ int is_leftaligned)
+{
+ if (is_leftaligned)
+ ((reference_T *)ref)->parameter->flags |= FLAGS_LEFTADJUST;
+ else
+ ((reference_T *)ref)->parameter->flags &= ~FLAGS_LEFTADJUST;
+}
+
+/*************************************************************************
+ * trio_get_spacing /trio_set_spacing [public]
+ */
+int
+trio_get_spacing(void *ref)
+{
+ return (((reference_T *)ref)->parameter->flags & FLAGS_SPACE);
+}
+
+void
+trio_set_spacing(void *ref,
+ int is_space)
+{
+ if (is_space)
+ ((reference_T *)ref)->parameter->flags |= FLAGS_SPACE;
+ else
+ ((reference_T *)ref)->parameter->flags &= ~FLAGS_SPACE;
+}
+
+/*************************************************************************
+ * trio_get_sign / trio_set_sign [public]
+ */
+int
+trio_get_sign(void *ref)
+{
+ return (((reference_T *)ref)->parameter->flags & FLAGS_SHOWSIGN);
+}
+
+void
+trio_set_sign(void *ref,
+ int is_sign)
+{
+ if (is_sign)
+ ((reference_T *)ref)->parameter->flags |= FLAGS_SHOWSIGN;
+ else
+ ((reference_T *)ref)->parameter->flags &= ~FLAGS_SHOWSIGN;
+}
+
+/*************************************************************************
+ * trio_get_padding / trio_set_padding [public]
+ */
+int
+trio_get_padding(void *ref)
+{
+ return (((reference_T *)ref)->parameter->flags & FLAGS_NILPADDING);
+}
+
+void
+trio_set_padding(void *ref,
+ int is_padding)
+{
+ if (is_padding)
+ ((reference_T *)ref)->parameter->flags |= FLAGS_NILPADDING;
+ else
+ ((reference_T *)ref)->parameter->flags &= ~FLAGS_NILPADDING;
+}
+
+/*************************************************************************
+ * trio_get_quote / trio_set_quote [public]
+ */
+int
+trio_get_quote(void *ref)
+{
+ return (((reference_T *)ref)->parameter->flags & FLAGS_QUOTE);
+}
+
+void
+trio_set_quote(void *ref,
+ int is_quote)
+{
+ if (is_quote)
+ ((reference_T *)ref)->parameter->flags |= FLAGS_QUOTE;
+ else
+ ((reference_T *)ref)->parameter->flags &= ~FLAGS_QUOTE;
+}
+
+/*************************************************************************
+ * trio_get_upper / trio_set_upper [public]
+ */
+int
+trio_get_upper(void *ref)
+{
+ return (((reference_T *)ref)->parameter->flags & FLAGS_UPPER);
+}
+
+void
+trio_set_upper(void *ref,
+ int is_upper)
+{
+ if (is_upper)
+ ((reference_T *)ref)->parameter->flags |= FLAGS_UPPER;
+ else
+ ((reference_T *)ref)->parameter->flags &= ~FLAGS_UPPER;
+}
+
+/*************************************************************************
+ * trio_get_largest / trio_set_largest [public]
+ */
+#if TRIO_C99
+int
+trio_get_largest(void *ref)
+{
+ return (((reference_T *)ref)->parameter->flags & FLAGS_INTMAX_T);
+}
+
+void
+trio_set_largest(void *ref,
+ int is_largest)
+{
+ if (is_largest)
+ ((reference_T *)ref)->parameter->flags |= FLAGS_INTMAX_T;
+ else
+ ((reference_T *)ref)->parameter->flags &= ~FLAGS_INTMAX_T;
+}
+#endif
+
+/*************************************************************************
+ * trio_get_ptrdiff / trio_set_ptrdiff [public]
+ */
+int
+trio_get_ptrdiff(void *ref)
+{
+ return (((reference_T *)ref)->parameter->flags & FLAGS_PTRDIFF_T);
+}
+
+void
+trio_set_ptrdiff(void *ref,
+ int is_ptrdiff)
+{
+ if (is_ptrdiff)
+ ((reference_T *)ref)->parameter->flags |= FLAGS_PTRDIFF_T;
+ else
+ ((reference_T *)ref)->parameter->flags &= ~FLAGS_PTRDIFF_T;
+}
+
+/*************************************************************************
+ * trio_get_size / trio_set_size [public]
+ */
+#if TRIO_C99
+int
+trio_get_size(void *ref)
+{
+ return (((reference_T *)ref)->parameter->flags & FLAGS_SIZE_T);
+}
+
+void
+trio_set_size(void *ref,
+ int is_size)
+{
+ if (is_size)
+ ((reference_T *)ref)->parameter->flags |= FLAGS_SIZE_T;
+ else
+ ((reference_T *)ref)->parameter->flags &= ~FLAGS_SIZE_T;
+}
+#endif
+
+/*************************************************************************
+ * trio_print_int [public]
+ */
+void
+trio_print_int(void *ref,
+ int number)
+{
+ reference_T *self = (reference_T *)ref;
+
+ TrioWriteNumber(self->data,
+ (trio_intmax_t)number,
+ self->parameter->flags,
+ self->parameter->width,
+ self->parameter->precision,
+ self->parameter->base);
+}
+
+/*************************************************************************
+ * trio_print_uint [public]
+ */
+void
+trio_print_uint(void *ref,
+ unsigned int number)
+{
+ reference_T *self = (reference_T *)ref;
+
+ TrioWriteNumber(self->data,
+ (trio_intmax_t)number,
+ self->parameter->flags | FLAGS_UNSIGNED,
+ self->parameter->width,
+ self->parameter->precision,
+ self->parameter->base);
+}
+
+/*************************************************************************
+ * trio_print_double [public]
+ */
+void
+trio_print_double(void *ref,
+ double number)
+{
+ reference_T *self = (reference_T *)ref;
+
+ TrioWriteDouble(self->data,
+ number,
+ self->parameter->flags,
+ self->parameter->width,
+ self->parameter->precision,
+ self->parameter->base);
+}
+
+/*************************************************************************
+ * trio_print_string [public]
+ */
+void
+trio_print_string(void *ref,
+ char *string)
+{
+ reference_T *self = (reference_T *)ref;
+
+ TrioWriteString(self->data,
+ string,
+ self->parameter->flags,
+ self->parameter->width,
+ self->parameter->precision);
+}
+
+/*************************************************************************
+ * trio_print_pointer [public]
+ */
+void
+trio_print_pointer(void *ref,
+ void *pointer)
+{
+ reference_T *self = (reference_T *)ref;
+ unsigned long flags;
+ trio_uintmax_t number;
+
+ if (NULL == pointer)
+ {
+ const char *string = null;
+ while (*string)
+ self->data->OutStream(self->data, *string++);
+ }
+ else
+ {
+ /*
+ * The subtraction of the null pointer is a workaround
+ * to avoid a compiler warning. The performance overhead
+ * is negligible (and likely to be removed by an
+ * optimising compiler). The (char *) casting is done
+ * to please ANSI C++.
+ */
+ number = (trio_uintmax_t)((char *)pointer - (char *)0);
+ /* Shrink to size of pointer */
+ number &= (trio_uintmax_t)-1;
+ flags = self->parameter->flags;
+ flags |= (FLAGS_UNSIGNED | FLAGS_ALTERNATIVE |
+ FLAGS_NILPADDING);
+ TrioWriteNumber(self->data,
+ (trio_intmax_t)number,
+ flags,
+ POINTER_WIDTH,
+ NO_PRECISION,
+ BASE_HEX);
+ }
+}
+
+/*************************************************************************
+ * trio_print_ref [public]
+ */
+int
+trio_print_ref(void *ref,
+ const char *format,
+ ...)
+{
+ int status;
+ va_list arglist;
+
+ assert(VALID(format));
+
+ va_start(arglist, format);
+ status = TrioFormatRef((reference_T *)ref, format, arglist, NULL);
+ va_end(arglist);
+ return status;
+}
+
+/*************************************************************************
+ * trio_vprint_ref [public]
+ */
+int
+trio_vprint_ref(void *ref,
+ const char *format,
+ va_list arglist)
+{
+ assert(VALID(format));
+
+ return TrioFormatRef((reference_T *)ref, format, arglist, NULL);
+}
+
+/*************************************************************************
+ * trio_printv_ref [public]
+ */
+int
+trio_printv_ref(void *ref,
+ const char *format,
+ void **argarray)
+{
+ va_list dummy;
+ shutup_unitialized(&dummy);
+
+ assert(VALID(format));
+
+ return TrioFormatRef((reference_T *)ref, format, dummy, argarray);
+}
+
+
+/*************************************************************************
+ *
+ * @SCANNING
+ *
+ ************************************************************************/
+
+
+/*************************************************************************
+ * TrioSkipWhitespaces [private]
+ */
+static int
+TrioSkipWhitespaces(trio_T *self)
+{
+ int ch;
+
+ ch = self->current;
+ while (isspace(ch))
+ {
+ self->InStream(self, &ch);
+ }
+ return ch;
+}
+
+/*************************************************************************
+ * TrioGetCollation [private]
+ */
+#if TRIO_EXTENSION
+static void
+TrioGetCollation()
+{
+ int i;
+ int j;
+ int k;
+ char first[2];
+ char second[2];
+
+ /* This is computational expensive */
+ first[1] = NIL;
+ second[1] = NIL;
+ for (i = 0; i < MAX_CHARACTER_CLASS; i++)
+ {
+ k = 0;
+ first[0] = (char)i;
+ for (j = 0; j < MAX_CHARACTER_CLASS; j++)
+ {
+ second[0] = (char)j;
+ if (StrEqualLocale(first, second))
+ internalCollationArray[i][k++] = (char)j;
+ }
+ internalCollationArray[i][k] = NIL;
+ }
+}
+#endif
+
+/*************************************************************************
+ * TrioGetCharacterClass [private]
+ *
+ * FIXME:
+ * multibyte
+ */
+static int
+TrioGetCharacterClass(const char *format,
+ int *indexPointer,
+ unsigned long *flagsPointer,
+ int *characterclass)
+{
+ int index = *indexPointer;
+ int i;
+ char ch;
+ char range_begin;
+ char range_end;
+
+ *flagsPointer &= ~FLAGS_EXCLUDE;
+
+ if (format[index] == QUALIFIER_CIRCUMFLEX)
+ {
+ *flagsPointer |= FLAGS_EXCLUDE;
+ index++;
+ }
+ /*
+ * If the ungroup character is at the beginning of the scanlist,
+ * it will be part of the class, and a second ungroup character
+ * must follow to end the group.
+ */
+ if (format[index] == SPECIFIER_UNGROUP)
+ {
+ characterclass[(int)SPECIFIER_UNGROUP]++;
+ index++;
+ }
+ /*
+ * Minus is used to specify ranges. To include minus in the class,
+ * it must be at the beginning of the list
+ */
+ if (format[index] == QUALIFIER_MINUS)
+ {
+ characterclass[(int)QUALIFIER_MINUS]++;
+ index++;
+ }
+ /* Collect characters */
+ for (ch = format[index];
+ (ch != SPECIFIER_UNGROUP) && (ch != NIL);
+ ch = format[++index])
+ {
+ switch (ch)
+ {
+ case QUALIFIER_MINUS: /* Scanlist ranges */
+
+ /*
+ * Both C99 and UNIX98 describes ranges as implementation-
+ * defined.
+ *
+ * We support the following behaviour (although this may
+ * change as we become wiser)
+ * - only increasing ranges, ie. [a-b] but not [b-a]
+ * - transitive ranges, ie. [a-b-c] == [a-c]
+ * - trailing minus, ie. [a-] is interpreted as an 'a'
+ * and a '-'
+ * - duplicates (although we can easily convert these
+ * into errors)
+ */
+ range_begin = format[index - 1];
+ range_end = format[++index];
+ if (range_end == SPECIFIER_UNGROUP)
+ {
+ /* Trailing minus is included */
+ characterclass[(int)ch]++;
+ ch = range_end;
+ break; /* for */
+ }
+ if (range_end == NIL)
+ return TRIO_ERROR_RETURN(TRIO_EINVAL, index);
+ if (range_begin > range_end)
+ return TRIO_ERROR_RETURN(TRIO_ERANGE, index);
+
+ for (i = (int)range_begin; i <= (int)range_end; i++)
+ characterclass[i]++;
+
+ ch = range_end;
+ break;
+
+#if TRIO_EXTENSION
+
+ case SPECIFIER_GROUP:
+
+ switch (format[index + 1])
+ {
+ case QUALIFIER_DOT: /* Collating symbol */
+ /*
+ * FIXME: This will be easier to implement when multibyte
+ * characters have been implemented. Until now, we ignore
+ * this feature.
+ */
+ for (i = index + 2; ; i++)
+ {
+ if (format[i] == NIL)
+ /* Error in syntax */
+ return -1;
+ else if (format[i] == QUALIFIER_DOT)
+ break; /* for */
+ }
+ if (format[++i] != SPECIFIER_UNGROUP)
+ return -1;
+
+ index = i;
+ break;
+
+ case QUALIFIER_EQUAL: /* Equivalence class expressions */
+ {
+ unsigned int j;
+ unsigned int k;
+
+ if (internalCollationUnconverted)
+ {
+ /* Lazy evalutation of collation array */
+ TrioGetCollation();
+ internalCollationUnconverted = FALSE;
+ }
+ for (i = index + 2; ; i++)
+ {
+ if (format[i] == NIL)
+ /* Error in syntax */
+ return -1;
+ else if (format[i] == QUALIFIER_EQUAL)
+ break; /* for */
+ else
+ {
+ /* Mark any equivalent character */
+ k = (unsigned int)format[i];
+ for (j = 0; internalCollationArray[k][j] != NIL; j++)
+ characterclass[(int)internalCollationArray[k][j]]++;
+ }
+ }
+ if (format[++i] != SPECIFIER_UNGROUP)
+ return -1;
+
+ index = i;
+ }
+ break;
+
+ case QUALIFIER_COLON: /* Character class expressions */
+
+ if (StrEqualMax(CLASS_ALNUM, sizeof(CLASS_ALNUM) - 1,
+ &format[index]))
+ {
+ for (i = 0; i < MAX_CHARACTER_CLASS; i++)
+ if (isalnum(i))
+ characterclass[i]++;
+ index += sizeof(CLASS_ALNUM) - 1;
+ }
+ else if (StrEqualMax(CLASS_ALPHA, sizeof(CLASS_ALPHA) - 1,
+ &format[index]))
+ {
+ for (i = 0; i < MAX_CHARACTER_CLASS; i++)
+ if (isalpha(i))
+ characterclass[i]++;
+ index += sizeof(CLASS_ALPHA) - 1;
+ }
+ else if (StrEqualMax(CLASS_CNTRL, sizeof(CLASS_CNTRL) - 1,
+ &format[index]))
+ {
+ for (i = 0; i < MAX_CHARACTER_CLASS; i++)
+ if (iscntrl(i))
+ characterclass[i]++;
+ index += sizeof(CLASS_CNTRL) - 1;
+ }
+ else if (StrEqualMax(CLASS_DIGIT, sizeof(CLASS_DIGIT) - 1,
+ &format[index]))
+ {
+ for (i = 0; i < MAX_CHARACTER_CLASS; i++)
+ if (isdigit(i))
+ characterclass[i]++;
+ index += sizeof(CLASS_DIGIT) - 1;
+ }
+ else if (StrEqualMax(CLASS_GRAPH, sizeof(CLASS_GRAPH) - 1,
+ &format[index]))
+ {
+ for (i = 0; i < MAX_CHARACTER_CLASS; i++)
+ if (isgraph(i))
+ characterclass[i]++;
+ index += sizeof(CLASS_GRAPH) - 1;
+ }
+ else if (StrEqualMax(CLASS_LOWER, sizeof(CLASS_LOWER) - 1,
+ &format[index]))
+ {
+ for (i = 0; i < MAX_CHARACTER_CLASS; i++)
+ if (islower(i))
+ characterclass[i]++;
+ index += sizeof(CLASS_LOWER) - 1;
+ }
+ else if (StrEqualMax(CLASS_PRINT, sizeof(CLASS_PRINT) - 1,
+ &format[index]))
+ {
+ for (i = 0; i < MAX_CHARACTER_CLASS; i++)
+ if (isprint(i))
+ characterclass[i]++;
+ index += sizeof(CLASS_PRINT) - 1;
+ }
+ else if (StrEqualMax(CLASS_PUNCT, sizeof(CLASS_PUNCT) - 1,
+ &format[index]))
+ {
+ for (i = 0; i < MAX_CHARACTER_CLASS; i++)
+ if (ispunct(i))
+ characterclass[i]++;
+ index += sizeof(CLASS_PUNCT) - 1;
+ }
+ else if (StrEqualMax(CLASS_SPACE, sizeof(CLASS_SPACE) - 1,
+ &format[index]))
+ {
+ for (i = 0; i < MAX_CHARACTER_CLASS; i++)
+ if (isspace(i))
+ characterclass[i]++;
+ index += sizeof(CLASS_SPACE) - 1;
+ }
+ else if (StrEqualMax(CLASS_UPPER, sizeof(CLASS_UPPER) - 1,
+ &format[index]))
+ {
+ for (i = 0; i < MAX_CHARACTER_CLASS; i++)
+ if (isupper(i))
+ characterclass[i]++;
+ index += sizeof(CLASS_UPPER) - 1;
+ }
+ else if (StrEqualMax(CLASS_XDIGIT, sizeof(CLASS_XDIGIT) - 1,
+ &format[index]))
+ {
+ for (i = 0; i < MAX_CHARACTER_CLASS; i++)
+ if (isxdigit(i))
+ characterclass[i]++;
+ index += sizeof(CLASS_XDIGIT) - 1;
+ }
+ else
+ {
+ characterclass[(int)ch]++;
+ }
+ break;
+
+ default:
+ characterclass[(int)ch]++;
+ break;
+ }
+ break;
+
+#endif /* TRIO_EXTENSION */
+
+ default:
+ characterclass[(int)ch]++;
+ break;
+ }
+ }
+ return 0;
+}
+
+/*************************************************************************
+ * TrioReadNumber [private]
+ *
+ * We implement our own number conversion in preference of strtol and
+ * strtoul, because we must handle 'long long' and thousand separators.
+ */
+static BOOLEAN_T
+TrioReadNumber(trio_T *self,
+ trio_uintmax_t *target,
+ unsigned long flags,
+ int width,
+ int base)
+{
+ trio_uintmax_t number = 0;
+ int digit;
+ int count;
+ BOOLEAN_T isNegative = FALSE;
+ int j;
+
+ assert(VALID(self));
+ assert(VALID(self->InStream));
+ assert((base >= MIN_BASE && base <= MAX_BASE) || (base == NO_BASE));
+
+ if (internalDigitsUnconverted)
+ {
+ /* Lazy evaluation of digits array */
+ memset(internalDigitArray, -1, sizeof(internalDigitArray));
+ for (j = 0; j < (int)sizeof(internalDigitsLower) - 1; j++)
+ {
+ internalDigitArray[(int)internalDigitsLower[j]] = j;
+ internalDigitArray[(int)internalDigitsUpper[j]] = j;
+ }
+ internalDigitsUnconverted = FALSE;
+ }
+
+ TrioSkipWhitespaces(self);
+
+ if (!(flags & FLAGS_UNSIGNED))
+ {
+ /* Leading sign */
+ if (self->current == '+')
+ {
+ self->InStream(self, NULL);
+ }
+ else if (self->current == '-')
+ {
+ self->InStream(self, NULL);
+ isNegative = TRUE;
+ }
+ }
+
+ count = self->processed;
+
+ if (flags & FLAGS_ALTERNATIVE)
+ {
+ switch (base)
+ {
+ case NO_BASE:
+ case BASE_OCTAL:
+ case BASE_HEX:
+ case BASE_BINARY:
+ if (self->current == '0')
+ {
+ self->InStream(self, NULL);
+ if (self->current)
+ {
+ if ((base == BASE_HEX) &&
+ (toupper(self->current) == 'X'))
+ {
+ self->InStream(self, NULL);
+ }
+ else if ((base == BASE_BINARY) &&
+ (toupper(self->current) == 'B'))
+ {
+ self->InStream(self, NULL);
+ }
+ }
+ }
+ else
+ return FALSE;
+ break;
+ default:
+ break;
+ }
+ }
+
+ while (((width == NO_WIDTH) || (self->processed - count < width)) &&
+ (! ((self->current == EOF) || isspace(self->current))))
+ {
+ if (isascii(self->current))
+ {
+ digit = internalDigitArray[self->current];
+ /* Abort if digit is not allowed in the specified base */
+ if ((digit == -1) || (digit >= base))
+ break;
+ }
+ else if (flags & FLAGS_QUOTE)
+ {
+ /* Compare with thousands separator */
+ for (j = 0; internalThousandSeparator[j] && self->current; j++)
+ {
+ if (internalThousandSeparator[j] != self->current)
+ break;
+
+ self->InStream(self, NULL);
+ }
+ if (internalThousandSeparator[j])
+ break; /* Mismatch */
+ else
+ continue; /* Match */
+ }
+ else
+ break;
+
+ number *= base;
+ number += digit;
+
+ self->InStream(self, NULL);
+ }
+
+ /* Was anything read at all? */
+ if (self->processed == count)
+ return FALSE;
+
+ if (target)
+ *target = (isNegative) ? -number : number;
+ return TRUE;
+}
+
+/*************************************************************************
+ * TrioReadChar [private]
+ */
+static int
+TrioReadChar(trio_T *self,
+ char *target,
+ unsigned long flags,
+ int width)
+{
+ int i;
+ char ch;
+ trio_uintmax_t number;
+
+ assert(VALID(self));
+ assert(VALID(self->InStream));
+
+ for (i = 0;
+ (self->current != EOF) && (i < width);
+ i++)
+ {
+ ch = (char)self->current;
+ self->InStream(self, NULL);
+ if ((flags & FLAGS_ALTERNATIVE) && (ch == CHAR_BACKSLASH))
+ {
+ switch (self->current)
+ {
+ case '\\': ch = '\\'; break;
+ case 'a': ch = '\007'; break;
+ case 'b': ch = '\b'; break;
+ case 'f': ch = '\f'; break;
+ case 'n': ch = '\n'; break;
+ case 'r': ch = '\r'; break;
+ case 't': ch = '\t'; break;
+ case 'v': ch = '\v'; break;
+ default:
+ if (isdigit(self->current))
+ {
+ /* Read octal number */
+ if (!TrioReadNumber(self, &number, 0, 3, BASE_OCTAL))
+ return 0;
+ ch = (char)number;
+ }
+ else if (toupper(self->current) == 'X')
+ {
+ /* Read hexadecimal number */
+ self->InStream(self, NULL);
+ if (!TrioReadNumber(self, &number, 0, 2, BASE_HEX))
+ return 0;
+ ch = (char)number;
+ }
+ else
+ {
+ ch = (char)self->current;
+ }
+ break;
+ }
+ }
+
+ if (target)
+ target[i] = ch;
+ }
+ return i + 1;
+}
+
+/*************************************************************************
+ * TrioReadString [private]
+ */
+static BOOLEAN_T
+TrioReadString(trio_T *self,
+ char *target,
+ unsigned long flags,
+ int width)
+{
+ int i;
+
+ assert(VALID(self));
+ assert(VALID(self->InStream));
+
+ TrioSkipWhitespaces(self);
+
+ /*
+ * Continue until end of string is reached, a whitespace is encountered,
+ * or width is exceeded
+ */
+ for (i = 0;
+ ((width == NO_WIDTH) || (i < width)) &&
+ (! ((self->current == EOF) || isspace(self->current)));
+ i++)
+ {
+ if (TrioReadChar(self, &target[i], flags, 1) == 0)
+ break; /* for */
+ }
+ if (target)
+ target[i] = NIL;
+ return TRUE;
+}
+
+/*************************************************************************
+ * TrioReadWideChar [private]
+ */
+#if TRIO_WIDECHAR
+static int
+TrioReadWideChar(trio_T *self,
+ wchar_t *target,
+ unsigned long flags,
+ int width)
+{
+ int i;
+ int j;
+ int size;
+ int amount = 0;
+ wchar_t wch;
+ char buffer[MB_LEN_MAX + 1];
+
+ assert(VALID(self));
+ assert(VALID(self->InStream));
+
+ for (i = 0;
+ (self->current != EOF) && (i < width);
+ i++)
+ {
+ if (isascii(self->current))
+ {
+ if (TrioReadChar(self, buffer, flags, 1) == 0)
+ return 0;
+ buffer[1] = NIL;
+ }
+ else
+ {
+ /*
+ * Collect a multibyte character, by enlarging buffer until
+ * it contains a fully legal multibyte character, or the
+ * buffer is full.
+ */
+ j = 0;
+ do
+ {
+ buffer[j++] = (char)self->current;
+ buffer[j] = NIL;
+ self->InStream(self, NULL);
+ }
+ while ((j < (int)sizeof(buffer)) && (mblen(buffer, (size_t)j) != j));
+ }
+ if (target)
+ {
+ size = mbtowc(&wch, buffer, sizeof(buffer));
+ if (size > 0)
+ target[i] = wch;
+ }
+ amount += size;
+ self->InStream(self, NULL);
+ }
+ return amount;
+}
+#endif /* TRIO_WIDECHAR */
+
+/*************************************************************************
+ * TrioReadWideString [private]
+ */
+#if TRIO_WIDECHAR
+static BOOLEAN_T
+TrioReadWideString(trio_T *self,
+ wchar_t *target,
+ unsigned long flags,
+ int width)
+{
+ int i;
+ int size;
+
+ assert(VALID(self));
+ assert(VALID(self->InStream));
+
+ TrioSkipWhitespaces(self);
+
+#if defined(TRIO_COMPILER_SUPPORTS_MULTIBYTE)
+ mblen(NULL, 0);
+#endif
+
+ /*
+ * Continue until end of string is reached, a whitespace is encountered,
+ * or width is exceeded
+ */
+ for (i = 0;
+ ((width == NO_WIDTH) || (i < width)) &&
+ (! ((self->current == EOF) || isspace(self->current)));
+ )
+ {
+ size = TrioReadWideChar(self, &target[i], flags, 1);
+ if (size == 0)
+ break; /* for */
+
+ i += size;
+ }
+ if (target)
+ target[i] = L'\0';
+ return TRUE;
+}
+#endif /* TRIO_WIDECHAR */
+
+/*************************************************************************
+ * TrioReadGroup [private]
+ *
+ * FIXME: characterclass does not work with multibyte characters
+ */
+static BOOLEAN_T
+TrioReadGroup(trio_T *self,
+ char *target,
+ int *characterclass,
+ unsigned long flags,
+ int width)
+{
+ int ch;
+ int i;
+
+ assert(VALID(self));
+ assert(VALID(self->InStream));
+
+ ch = self->current;
+ for (i = 0;
+ ((width == NO_WIDTH) || (i < width)) &&
+ (! ((ch == EOF) ||
+ (((flags & FLAGS_EXCLUDE) != 0) ^ (characterclass[ch] == 0))));
+ i++)
+ {
+ if (target)
+ target[i] = (char)ch;
+ self->InStream(self, &ch);
+ }
+
+ if (target)
+ target[i] = NIL;
+ return TRUE;
+}
+
+/*************************************************************************
+ * TrioReadDouble [private]
+ *
+ * FIXME:
+ * add long double
+ */
+static BOOLEAN_T
+TrioReadDouble(trio_T *self,
+ double *target,
+ unsigned long flags,
+ int width)
+{
+ int ch;
+ char doubleString[512] = "";
+ int index = 0;
+ int start;
+ int j;
+ BOOLEAN_T isHex = FALSE;
+
+ if ((width == NO_WIDTH) || (width > (int)sizeof(doubleString) - 1))
+ width = sizeof(doubleString) - 1;
+
+ TrioSkipWhitespaces(self);
+
+ /*
+ * Read entire double number from stream. StrToDouble requires a
+ * string as input, but InStream can be anything, so we have to
+ * collect all characters.
+ */
+ ch = self->current;
+ if ((ch == '+') || (ch == '-'))
+ {
+ doubleString[index++] = (char)ch;
+ self->InStream(self, &ch);
+ width--;
+ }
+
+ start = index;
+ switch (ch)
+ {
+ case 'n':
+ case 'N':
+ /* Not-a-number */
+ if (index != 0)
+ break;
+ /* FALLTHROUGH */
+ case 'i':
+ case 'I':
+ /* Infinity */
+ while (isalpha(ch) && (index - start < width))
+ {
+ doubleString[index++] = (char)ch;
+ self->InStream(self, &ch);
+ }
+ doubleString[index] = NIL;
+
+ /* Case insensitive string comparison */
+ if (StrEqual(&doubleString[start], INFINITE_UPPER) ||
+ StrEqual(&doubleString[start], LONG_INFINITE_UPPER))
+ {
+ *target = ((start == 1 && doubleString[0] == '-'))
+ ? -HUGE_VAL
+ : HUGE_VAL;
+ return TRUE;
+ }
+ if (StrEqual(doubleString, NAN_LOWER))
+ {
+ /* NaN must not have a preceeding + nor - */
+ *target = TrioGenerateNaN();
+ return TRUE;
+ }
+ return FALSE;
+
+ default:
+ break;
+ }
+
+ if (ch == '0')
+ {
+ doubleString[index++] = (char)ch;
+ self->InStream(self, &ch);
+ if (toupper(ch) == 'X')
+ {
+ isHex = TRUE;
+ doubleString[index++] = (char)ch;
+ self->InStream(self, &ch);
+ }
+ }
+ while ((ch != EOF) && (index - start < width))
+ {
+ /* Integer part */
+ if (isHex ? isxdigit(ch) : isdigit(ch))
+ {
+ doubleString[index++] = (char)ch;
+ self->InStream(self, &ch);
+ }
+ else if (flags & FLAGS_QUOTE)
+ {
+ /* Compare with thousands separator */
+ for (j = 0; internalThousandSeparator[j] && self->current; j++)
+ {
+ if (internalThousandSeparator[j] != self->current)
+ break;
+
+ self->InStream(self, &ch);
+ }
+ if (internalThousandSeparator[j])
+ break; /* Mismatch */
+ else
+ continue; /* Match */
+ }
+ else
+ break; /* while */
+ }
+ if (ch == '.')
+ {
+ /* Decimal part */
+ doubleString[index++] = (char)ch;
+ self->InStream(self, &ch);
+ while ((isHex ? isxdigit(ch) : isdigit(ch)) &&
+ (index - start < width))
+ {
+ doubleString[index++] = (char)ch;
+ self->InStream(self, &ch);
+ }
+ if (isHex ? (toupper(ch) == 'P') : (toupper(ch) == 'E'))
+ {
+ /* Exponent */
+ doubleString[index++] = (char)ch;
+ self->InStream(self, &ch);
+ if ((ch == '+') || (ch == '-'))
+ {
+ doubleString[index++] = (char)ch;
+ self->InStream(self, &ch);
+ }
+ while ((isHex ? isxdigit(ch) : isdigit(ch)) &&
+ (index - start < width))
+ {
+ doubleString[index++] = (char)ch;
+ self->InStream(self, &ch);
+ }
+ }
+ }
+
+ if ((index == start) || (*doubleString == NIL))
+ return FALSE;
+
+ if (flags & FLAGS_LONGDOUBLE)
+/* *longdoublePointer = StrToLongDouble()*/
+ return FALSE; /* FIXME: Remove when long double is implemented */
+ else
+ {
+ *target = StrToDouble(doubleString, NULL);
+ }
+ return TRUE;
+}
+
+/*************************************************************************
+ * TrioReadPointer [private]
+ */
+static BOOLEAN_T
+TrioReadPointer(trio_T *self,
+ void **target,
+ unsigned long flags)
+{
+ trio_uintmax_t number;
+ char buffer[sizeof(null)];
+
+ flags |= (FLAGS_UNSIGNED | FLAGS_ALTERNATIVE | FLAGS_NILPADDING);
+
+ if (TrioReadNumber(self,
+ &number,
+ flags,
+ POINTER_WIDTH,
+ BASE_HEX))
+ {
+ /*
+ * The strange assignment of number is a workaround for a compiler
+ * warning
+ */
+ if (target)
+ *target = (char *)0 + number;
+ return TRUE;
+ }
+ else if (TrioReadString(self,
+ (flags & FLAGS_IGNORE)
+ ? NULL
+ : buffer,
+ 0,
+ sizeof(null) - 1))
+ {
+ if (StrEqualCase(buffer, null))
+ {
+ if (target)
+ *target = NULL;
+ return TRUE;
+ }
+ }
+ return FALSE;
+}
+
+/*************************************************************************
+ * TrioScan [private]
+ */
+static int
+TrioScan(const void *source,
+ size_t sourceSize,
+ void (*InStream)(trio_T *, int *),
+ const char *format,
+ va_list arglist,
+ void **argarray)
+{
+#if defined(TRIO_COMPILER_SUPPORTS_MULTIBYTE)
+ int charlen;
+#endif
+ int status;
+ int assignment;
+ parameter_T parameters[MAX_PARAMETERS];
+ trio_T internalData;
+ trio_T *data;
+ int ch;
+#if defined(TRIO_COMPILER_SUPPORTS_MULTIBYTE)
+ int cnt;
+#endif
+ int index; /* Index of format string */
+ int i; /* Index of current parameter */
+ unsigned long flags;
+ int width;
+ int base;
+ void *pointer;
+
+ assert(VALID(InStream));
+ assert(VALID(format));
+
+ memset(&internalData, 0, sizeof(internalData));
+ data = &internalData;
+ data->InStream = InStream;
+ data->location = (void *)source;
+ data->max = sourceSize;
+
+#if defined(USE_LOCALE)
+ if (NULL == internalLocaleValues)
+ {
+ TrioSetLocale();
+ }
+#endif
+
+ status = TrioPreprocess(TYPE_SCAN, format, parameters, arglist, argarray);
+ if (status < 0)
+ return status;
+
+ assignment = 0;
+ i = 0;
+ index = 0;
+ data->InStream(data, &ch);
+
+#if defined(TRIO_COMPILER_SUPPORTS_MULTIBYTE)
+ mblen(NULL, 0);
+#endif
+
+ while (format[index])
+ {
+#if defined(TRIO_COMPILER_SUPPORTS_MULTIBYTE)
+ if (! isascii(format[index]))
+ {
+ charlen = mblen(&format[index], MB_LEN_MAX);
+ /* Compare multibyte characters in format string */
+ for (cnt = 0; cnt < charlen - 1; cnt++)
+ {
+ if (ch != format[index + cnt])
+ {
+ return TRIO_ERROR_RETURN(TRIO_EINVAL, index);
+ }
+ data->InStream(data, &ch);
+ }
+ continue; /* while */
+ }
+#endif /* TRIO_COMPILER_SUPPORTS_MULTIBYTE */
+ if (EOF == ch)
+ return EOF;
+
+ if (CHAR_IDENTIFIER == format[index])
+ {
+ if (CHAR_IDENTIFIER == format[index + 1])
+ {
+ /* Two % in format matches one % in input stream */
+ if (CHAR_IDENTIFIER == ch)
+ {
+ data->InStream(data, &ch);
+ index += 2;
+ continue; /* while format chars left */
+ }
+ else
+ return TRIO_ERROR_RETURN(TRIO_EINVAL, index);
+ }
+
+ /* Skip the parameter entries */
+ while (parameters[i].type == FORMAT_PARAMETER)
+ i++;
+
+ flags = parameters[i].flags;
+ /* Find width */
+ width = parameters[i].width;
+ if (flags & FLAGS_WIDTH_PARAMETER)
+ {
+ /* Get width from parameter list */
+ width = (int)parameters[width].data.number.as_signed;
+ }
+ /* Find base */
+ base = parameters[i].base;
+ if (flags & FLAGS_BASE_PARAMETER)
+ {
+ /* Get base from parameter list */
+ base = (int)parameters[base].data.number.as_signed;
+ }
+
+ switch (parameters[i].type)
+ {
+ case FORMAT_INT:
+ {
+ trio_uintmax_t number;
+
+ if (0 == base)
+ base = BASE_DECIMAL;
+
+ if (!TrioReadNumber(data,
+ &number,
+ flags,
+ width,
+ base))
+ return assignment;
+ assignment++;
+
+ if (!(flags & FLAGS_IGNORE))
+ {
+ pointer = parameters[i].data.pointer;
+#if defined(QUALIFIER_SIZE_T) || defined(QUALIFIER_SIZE_T_UPPER)
+ if (flags & FLAGS_SIZE_T)
+ *(size_t *)pointer = (size_t)number;
+ else
+#endif
+#if defined(QUALIFIER_PTRDIFF_T)
+ if (flags & FLAGS_PTRDIFF_T)
+ *(ptrdiff_t *)pointer = (ptrdiff_t)number;
+ else
+#endif
+#if defined(QUALIFIER_INTMAX_T)
+ if (flags & FLAGS_INTMAX_T)
+ *(trio_intmax_t *)pointer = (trio_intmax_t)number;
+ else
+#endif
+ if (flags & FLAGS_QUAD)
+ *(trio_ulonglong_t *)pointer = (trio_ulonglong_t)number;
+ else if (flags & FLAGS_LONG)
+ *(long int *)pointer = (long int)number;
+ else if (flags & FLAGS_SHORT)
+ *(short int *)pointer = (short int)number;
+ else
+ *(int *)pointer = (int)number;
+ }
+ }
+ break; /* FORMAT_INT */
+
+ case FORMAT_STRING:
+#if TRIO_WIDECHAR
+ if (flags & FLAGS_WIDECHAR)
+ {
+ if (!TrioReadWideString(data,
+ (flags & FLAGS_IGNORE)
+ ? NULL
+ : parameters[i].data.wstring,
+ flags,
+ width))
+ return assignment;
+ }
+ else
+#endif
+ {
+ if (!TrioReadString(data,
+ (flags & FLAGS_IGNORE)
+ ? NULL
+ : parameters[i].data.string,
+ flags,
+ width))
+ return assignment;
+ }
+ assignment++;
+ break; /* FORMAT_STRING */
+
+ case FORMAT_DOUBLE:
+ if (!TrioReadDouble(data,
+ (flags & FLAGS_IGNORE)
+ ? NULL
+ : parameters[i].data.doublePointer,
+ flags,
+ width))
+ return assignment;
+ assignment++;
+ break; /* FORMAT_DOUBLE */
+
+ case FORMAT_GROUP:
+ {
+ int characterclass[MAX_CHARACTER_CLASS + 1];
+ int rc;
+
+ /* Skip over modifiers */
+ while (format[index] != SPECIFIER_GROUP)
+ {
+ index++;
+ }
+ /* Skip over group specifier */
+ index++;
+
+ memset(characterclass, 0, sizeof(characterclass));
+ rc = TrioGetCharacterClass(format,
+ &index,
+ &flags,
+ characterclass);
+ if (rc < 0)
+ return rc;
+
+ if (!TrioReadGroup(data,
+ (flags & FLAGS_IGNORE)
+ ? NULL
+ : parameters[i].data.string,
+ characterclass,
+ flags,
+ parameters[i].width))
+ return assignment;
+ assignment++;
+ }
+ break; /* FORMAT_GROUP */
+
+ case FORMAT_COUNT:
+ pointer = parameters[i].data.pointer;
+ if (NULL != pointer)
+ {
+#if defined(QUALIFIER_SIZE_T) || defined(QUALIFIER_SIZE_T_UPPER)
+ if (flags & FLAGS_SIZE_T)
+ *(size_t *)pointer = (size_t)data->committed;
+ else
+#endif
+#if defined(QUALIFIER_PTRDIFF_T)
+ if (flags & FLAGS_PTRDIFF_T)
+ *(ptrdiff_t *)pointer = (ptrdiff_t)data->committed;
+ else
+#endif
+#if defined(QUALIFIER_INTMAX_T)
+ if (flags & FLAGS_INTMAX_T)
+ *(trio_intmax_t *)pointer = (trio_intmax_t)data->committed;
+ else
+#endif
+ if (flags & FLAGS_QUAD)
+ {
+ *(trio_ulonglong_t *)pointer = (trio_ulonglong_t)data->committed;
+ }
+ else if (flags & FLAGS_LONG)
+ {
+ *(long int *)pointer = (long int)data->committed;
+ }
+ else if (flags & FLAGS_SHORT)
+ {
+ *(short int *)pointer = (short int)data->committed;
+ }
+ else
+ {
+ *(int *)pointer = (int)data->committed;
+ }
+ }
+ break; /* FORMAT_COUNT */
+
+ case FORMAT_CHAR:
+#if TRIO_WIDECHAR
+ if (flags & FLAGS_WIDECHAR)
+ {
+ if (TrioReadWideChar(data,
+ (flags & FLAGS_IGNORE)
+ ? NULL
+ : parameters[i].data.wstring,
+ flags,
+ (width == NO_WIDTH) ? 1 : width) > 0)
+ return assignment;
+ }
+ else
+#endif
+ {
+ if (TrioReadChar(data,
+ (flags & FLAGS_IGNORE)
+ ? NULL
+ : parameters[i].data.string,
+ flags,
+ (width == NO_WIDTH) ? 1 : width) > 0)
+ return assignment;
+ }
+ assignment++;
+ break; /* FORMAT_CHAR */
+
+ case FORMAT_POINTER:
+ if (!TrioReadPointer(data,
+ (flags & FLAGS_IGNORE)
+ ? NULL
+ : (void **)parameters[i].data.pointer,
+ flags))
+ return assignment;
+ assignment++;
+ break; /* FORMAT_POINTER */
+
+ case FORMAT_PARAMETER:
+ break; /* FORMAT_PARAMETER */
+
+ default:
+ return TRIO_ERROR_RETURN(TRIO_EINVAL, index);
+ }
+ ch = data->current;
+ index = parameters[i].indexAfterSpecifier;
+ i++;
+ }
+ else /* Not an % identifier */
+ {
+ if (isspace((int)format[index]))
+ {
+ /* Whitespaces may match any amount of whitespaces */
+ ch = TrioSkipWhitespaces(data);
+ }
+ else if (ch == format[index])
+ {
+ data->InStream(data, &ch);
+ }
+ else
+ return TRIO_ERROR_RETURN(TRIO_EINVAL, index);
+
+ index++;
+ }
+ }
+ return assignment;
+}
+
+/*************************************************************************
+ * TrioInStreamFile [private]
+ */
+static void
+TrioInStreamFile(trio_T *self,
+ int *intPointer)
+{
+ FILE *file = (FILE *)self->location;
+
+ assert(VALID(self));
+ assert(VALID(file));
+
+ self->current = fgetc(file);
+ self->processed++;
+ self->committed++;
+
+ if (VALID(intPointer))
+ {
+ *intPointer = self->current;
+ }
+}
+
+/*************************************************************************
+ * TrioInStreamFileDescriptor [private]
+ */
+static void
+TrioInStreamFileDescriptor(trio_T *self,
+ int *intPointer)
+{
+ int fd = *((int *)self->location);
+ int size;
+ unsigned char input;
+
+ assert(VALID(self));
+
+ size = read(fd, &input, sizeof(char));
+ self->current = (size == 0) ? EOF : input;
+ self->processed++;
+ self->committed++;
+
+ if (VALID(intPointer))
+ {
+ *intPointer = self->current;
+ }
+}
+
+/*************************************************************************
+ * TrioInStreamString [private]
+ */
+static void
+TrioInStreamString(trio_T *self,
+ int *intPointer)
+{
+ unsigned char **buffer;
+
+ assert(VALID(self));
+ assert(VALID(self->InStream));
+ assert(VALID(self->location));
+
+ buffer = (unsigned char **)self->location;
+ self->current = (*buffer)[0];
+ if (self->current == NIL)
+ self->current = EOF;
+ (*buffer)++;
+ self->processed++;
+ self->committed++;
+
+ if (VALID(intPointer))
+ {
+ *intPointer = self->current;
+ }
+}
+
+/*************************************************************************
+ * scanf
+ */
+int
+trio_scanf(const char *format,
+ ...)
+{
+ int status;
+ va_list args;
+
+ assert(VALID(format));
+
+ va_start(args, format);
+ status = TrioScan(stdin, 0, TrioInStreamFile, format, args, NULL);
+ va_end(args);
+ return status;
+}
+
+int
+trio_vscanf(const char *format,
+ va_list args)
+{
+ assert(VALID(format));
+
+ return TrioScan(stdin, 0, TrioInStreamFile, format, args, NULL);
+}
+
+int
+trio_scanfv(const char *format,
+ void **args)
+{
+ va_list dummy;
+ shutup_unitialized(&dummy);
+
+ assert(VALID(format));
+
+ return TrioScan(stdin, 0, TrioInStreamFile, format, dummy, args);
+}
+
+/*************************************************************************
+ * fscanf
+ */
+int
+trio_fscanf(FILE *file,
+ const char *format,
+ ...)
+{
+ int status;
+ va_list args;
+
+ assert(VALID(file));
+ assert(VALID(format));
+
+ va_start(args, format);
+ status = TrioScan(file, 0, TrioInStreamFile, format, args, NULL);
+ va_end(args);
+ return status;
+}
+
+int
+trio_vfscanf(FILE *file,
+ const char *format,
+ va_list args)
+{
+ assert(VALID(file));
+ assert(VALID(format));
+
+ return TrioScan(file, 0, TrioInStreamFile, format, args, NULL);
+}
+
+int
+trio_fscanfv(FILE *file,
+ const char *format,
+ void **args)
+{
+ va_list dummy;
+ shutup_unitialized(&dummy);
+
+ assert(VALID(file));
+ assert(VALID(format));
+
+ return TrioScan(file, 0, TrioInStreamFile, format, dummy, args);
+}
+
+/*************************************************************************
+ * dscanf
+ */
+int
+trio_dscanf(int fd,
+ const char *format,
+ ...)
+{
+ int status;
+ va_list args;
+
+ assert(VALID(format));
+
+ va_start(args, format);
+ status = TrioScan(&fd, 0, TrioInStreamFileDescriptor, format, args, NULL);
+ va_end(args);
+ return status;
+}
+
+int
+trio_vdscanf(int fd,
+ const char *format,
+ va_list args)
+{
+ assert(VALID(format));
+
+ return TrioScan(&fd, 0, TrioInStreamFileDescriptor, format, args, NULL);
+}
+
+int
+trio_dscanfv(int fd,
+ const char *format,
+ void **args)
+{
+ va_list dummy;
+ shutup_unitialized(&dummy);
+
+ assert(VALID(format));
+
+ return TrioScan(&fd, 0, TrioInStreamFileDescriptor, format, dummy, args);
+}
+
+/*************************************************************************
+ * sscanf
+ */
+int
+trio_sscanf(const char *buffer,
+ const char *format,
+ ...)
+{
+ int status;
+ va_list args;
+
+ assert(VALID(buffer));
+ assert(VALID(format));
+
+ va_start(args, format);
+ status = TrioScan(&buffer, 0, TrioInStreamString, format, args, NULL);
+ va_end(args);
+ return status;
+}
+
+int
+trio_vsscanf(const char *buffer,
+ const char *format,
+ va_list args)
+{
+ assert(VALID(buffer));
+ assert(VALID(format));
+
+ return TrioScan(&buffer, 0, TrioInStreamString, format, args, NULL);
+}
+
+int
+trio_sscanfv(const char *buffer,
+ const char *format,
+ void **args)
+{
+ va_list dummy;
+ shutup_unitialized(&dummy);
+
+ assert(VALID(buffer));
+ assert(VALID(format));
+
+ return TrioScan(&buffer, 0, TrioInStreamString, format, dummy, args);
+}
+
--- /dev/null
+/*************************************************************************
+ *
+ * $Id$
+ *
+ * Copyright (C) 2000 Bjorn Reese and Daniel Stenberg.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
+ * MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE AUTHORS AND
+ * CONTRIBUTORS ACCEPT NO RESPONSIBILITY IN ANY CONCEIVABLE MANNER.
+ *
+ ************************************************************************
+ *
+ * Private functions, types, etc. used for callback functions.
+ *
+ * The ref pointer is an opaque type and should remain as such.
+ * Private data must only be accessible through the getter and
+ * setter functions.
+ *
+ ************************************************************************/
+
+#ifndef TRIO_TRIOP_H
+#define TRIO_TRIOP_H
+
+#include <stdlib.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifndef TRIO_C99
+# define TRIO_C99 1
+#endif
+#ifndef TRIO_BSD
+# define TRIO_BSD 1
+#endif
+#ifndef TRIO_GNU
+# define TRIO_GNU 1
+#endif
+#ifndef TRIO_MISC
+# define TRIO_MISC 1
+#endif
+#ifndef TRIO_UNIX98
+# define TRIO_UNIX98 1
+#endif
+#ifndef TRIO_MICROSOFT
+# define TRIO_MICROSOFT 1
+#endif
+#ifndef TRIO_EXTENSION
+# define TRIO_EXTENSION 1
+#endif
+#ifndef TRIO_WIDECHAR
+# define TRIO_WIDECHAR 0
+#endif
+#ifndef TRIO_ERRORS
+# define TRIO_ERRORS 1
+#endif
+
+#ifndef TRIO_MALLOC
+# define TRIO_MALLOC(n) malloc(n)
+#endif
+#ifndef TRIO_REALLOC
+# define TRIO_REALLOC(x,n) realloc((x),(n))
+#endif
+#ifndef TRIO_FREE
+# define TRIO_FREE(x) free(x)
+#endif
+
+typedef int (*trio_callback_t)(void *ref);
+
+void *trio_register(trio_callback_t callback, const char *name);
+void trio_unregister(void *handle);
+
+const char *trio_get_format(void *ref);
+void *trio_get_argument(void *ref);
+
+/* Modifiers */
+int trio_get_width(void *ref);
+void trio_set_width(void *ref, int width);
+int trio_get_precision(void *ref);
+void trio_set_precision(void *ref, int precision);
+int trio_get_base(void *ref);
+void trio_set_base(void *ref, int base);
+int trio_get_padding(void *ref);
+void trio_set_padding(void *ref, int is_padding);
+int trio_get_short(void *ref); /* h */
+void trio_set_shortshort(void *ref, int is_shortshort);
+int trio_get_shortshort(void *ref); /* hh */
+void trio_set_short(void *ref, int is_short);
+int trio_get_long(void *ref); /* l */
+void trio_set_long(void *ref, int is_long);
+int trio_get_longlong(void *ref); /* ll */
+void trio_set_longlong(void *ref, int is_longlong);
+int trio_get_longdouble(void *ref); /* L */
+void trio_set_longdouble(void *ref, int is_longdouble);
+int trio_get_alternative(void *ref); /* # */
+void trio_set_alternative(void *ref, int is_alternative);
+int trio_get_alignment(void *ref); /* - */
+void trio_set_alignment(void *ref, int is_leftaligned);
+int trio_get_spacing(void *ref); /* (space) */
+void trio_set_spacing(void *ref, int is_space);
+int trio_get_sign(void *ref); /* + */
+void trio_set_sign(void *ref, int is_showsign);
+int trio_get_quote(void *ref); /* ' */
+void trio_set_quote(void *ref, int is_quote);
+int trio_get_upper(void *ref);
+void trio_set_upper(void *ref, int is_upper);
+#if TRIO_C99
+int trio_get_largest(void *ref); /* j */
+void trio_set_largest(void *ref, int is_largest);
+int trio_get_ptrdiff(void *ref); /* t */
+void trio_set_ptrdiff(void *ref, int is_ptrdiff);
+int trio_get_size(void *ref); /* z / Z */
+void trio_set_size(void *ref, int is_size);
+#endif
+
+/* Printing */
+int trio_print_ref(void *ref, const char *format, ...);
+int trio_vprint_ref(void *ref, const char *format, va_list args);
+int trio_printv_ref(void *ref, const char *format, void **args);
+
+void trio_print_int(void *ref, int number);
+void trio_print_uint(void *ref, unsigned int number);
+/* void trio_print_long(void *ref, long number); */
+/* void trio_print_ulong(void *ref, unsigned long number); */
+void trio_print_double(void *ref, double number);
+void trio_print_string(void *ref, char *string);
+void trio_print_pointer(void *ref, void *pointer);
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif
+
+#endif /* TRIO_TRIOP_H */
--- /dev/null
+#ident "$Header$"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+#include <ctype.h>
+#include <errno.h>
+
+/*========= DATA =====================================================*/
+
+#include "ulm_parse.h"
+
+/*========= FUNCTIONS ================================================*/
+
+/* -- Internal function prototype -- */
+void edg_wll_ULMSplitDate( const char *s,
+ unsigned int *year,
+ unsigned int *mon,
+ unsigned int *day,
+ unsigned int *hour,
+ unsigned int *min,
+ unsigned int *sec,
+ unsigned long *usec );
+int edg_wll_ULMisalphaext( int c);
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * edg_wll_ULMNewParseTable -- Allocate memory for new parse table
+ *
+ * Calls: malloc, strdup
+ *
+ * Algorithm:
+ *
+ *----------------------------------------------------------------------
+ */
+p_edg_wll_ULMFields edg_wll_ULMNewParseTable(LogLine logline)
+{
+ p_edg_wll_ULMFields this = (p_edg_wll_ULMFields) calloc(1,sizeof(edg_wll_ULMFields));
+ LogLine ln = logline;
+
+ /* Strip leading spaces */
+ for ( ; *ln && isblank(*ln); ln++ );
+
+ this->names = NULL;
+ this->vals = NULL;
+ this->num = 0;
+ this->raw = strdup(ln);
+
+ return this;
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * edg_wll_ULMFreeParseTable -- Free memory allocated for parse table
+ *
+ * Calls: free
+ *
+ * Algorithm:
+ *
+ *----------------------------------------------------------------------
+ */
+void edg_wll_ULMFreeParseTable(p_edg_wll_ULMFields this)
+{
+ EDG_WLL_ULM_CLEAR_FIELDS(this);
+ if (this->raw) free(this->raw);
+ if (this) free(this);
+}
+
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * edg_wll_ULMProcessParseTable -- Break UML message into fields.
+ *
+ * Calls: strchr, strrchr
+ *
+ * Algorithm:
+ * LogLine is of the ULM form as described in draft-abela-ulm-05.
+ * - the ULM_EQ symbol separates name,value pairs
+ * - quote marks must be taken into account
+ * 1. count ULM_EQ and ULM_SP symbols,
+ * 2. allocate the integer arrays 'names' and 'vals' which hold
+ * the indices of subsequent name and value strings,
+ * 3. the original raw data will be peppered with \0's so that raw[index]
+ * will give the proper string if index is in names[] or vals[]
+ *
+ * The actual algorithm to get these indices is a simple array lookup.
+ *
+ * The following illegal formats are caught:
+ * 1. no name=value pairs
+ * 2. space or tab next to delimiter
+ * 3. logline starts or ends with delimiter
+ * 4. no spaces between successive delimiters
+ * 5. illegal character after ending ULM_QM
+ *
+ *----------------------------------------------------------------------
+ */
+int edg_wll_ULMProcessParseTable(p_edg_wll_ULMFields this)
+{
+ char *func = "edg_wll_ULMProcessParseTable";
+ char *eq;
+ int i,j;
+ int eqCnt,qmCnt,spCnt;
+ int iArrayEQ[ULM_FIELDS_MAX];
+ int iArraySP[ULM_FIELDS_MAX];
+ size_t size;
+
+ if ( (this == NULL) || (this->raw == NULL) || (*this->raw == '\0')) {
+ fprintf(stderr,"%s: PARSE ERROR: Nothing to parse.\n",func);
+ return ULM_PARSE_ERROR;
+ }
+
+ /* Init data */
+ EDG_WLL_ULM_CLEAR_FIELDS(this);
+
+ for (i=0; i<ULM_FIELDS_MAX; i++) {
+ iArrayEQ[i] = 0;
+ iArraySP[i] = 0;
+ }
+
+ i = j = 0;
+ qmCnt = eqCnt = spCnt = 0;
+
+ size = strlen(this->raw);
+
+ /* Count number of ULM_EQ and ULM_SP
+ * and replace all ULM_LF by nul characters */
+ for (i=0; i< (int)size; i++) {
+ switch (this->raw[i]) {
+ case ULM_SP :
+ case ULM_TB :
+ if (qmCnt == 0) { iArraySP[spCnt] = i; spCnt++; }
+ break;
+ case ULM_EQ :
+ if (i==0) {
+ fprintf(stderr,"%s: PARSE ERROR: '%c' at the beginning of log line.\n", func, ULM_EQ);
+ return ULM_PARSE_ERROR;
+ }
+ if (qmCnt == 0) {
+ if (isblank(this->raw[i-1]) || (!edg_wll_ULMisalphaext(this->raw[i-1]))) {
+ fprintf(stderr,"%s: PARSE ERROR: Disallowed character ('%c') or space before delimiter '%c'.\n",
+ func,this->raw[i-1],ULM_EQ);
+ return ULM_PARSE_ERROR;
+ }
+ if (isblank(this->raw[i+1]) || ((!edg_wll_ULMisalphaext(this->raw[i-1])) && (this->raw[i+1] != ULM_QM ))) {
+ fprintf(stderr,"%s: PARSE ERROR: Disallowed character ('%c') or space after delimiter '%c'.\n",
+ func,this->raw[i+1],ULM_EQ);
+ return ULM_PARSE_ERROR;
+ }
+ iArrayEQ[eqCnt] = i;
+ eqCnt++;
+ }
+ break;
+ case ULM_LF :
+ if (qmCnt == 0) { this->raw[i] = '\0'; }
+ break;
+ case ULM_QM :
+ if (this->raw[i-1] != ULM_BS) {
+ if (qmCnt == 0) qmCnt++;
+ else qmCnt--;
+ }
+ if ((qmCnt == 0) && (!isspace(this->raw[i+1]) && (this->raw[i+1] != '\0'))) {
+ fprintf(stderr,"%s: PARSE ERROR: Disallowed character ('%c') after ending '%c'at i=%d size=%d char=%d.\n",
+ func,this->raw[i+1],ULM_QM,i,size,this->raw[i+1]);
+ for (j=0; j<=i; j++) fputc(this->raw[j],stderr);
+ fputc(ULM_LF,stderr);
+ return ULM_PARSE_ERROR;
+ }
+ break;
+ default :
+ break;
+ } /* switch */
+ } /* for */
+
+ if (eqCnt == 0) {
+ fprintf(stderr,"%s: PARSE ERROR: No '%c' in line \"%s\"\n",func,ULM_EQ,this->raw);
+ return ULM_PARSE_ERROR;
+ }
+
+ if (this->raw[0] == ULM_EQ) {
+ fprintf(stderr,"%s: PARSE ERROR: Need at least 1 letter for the first field name.\n",func);
+ return ULM_PARSE_ERROR;
+ }
+
+ if (qmCnt != 0) {
+ fprintf(stderr,"%s: PARSE ERROR: Last quoted value did not finish.\n",func);
+ return ULM_PARSE_ERROR;
+ }
+
+ /* Allocate names, vals arrays */
+ this->names = (int *) malloc(eqCnt*sizeof(int));
+ this->vals = (int *) malloc(eqCnt*sizeof(int));
+
+ this->names[0] = (int)(0);
+ this->vals[0] = (int)(iArrayEQ[0] + 1);
+
+ /*
+ * Main loop
+ */
+ for (i=1; i<eqCnt; i++) {
+ eq = &this->raw[iArrayEQ[i]];
+ j = 1;
+ while (edg_wll_ULMisalphaext(*(eq-j))) {
+ j++;
+ }
+ if (isblank(*(eq-j))) {
+ this->names[i] = (int)(iArrayEQ[i] - j + 1);
+ this->vals[i] = (int)(iArrayEQ[i] + 1);
+ }
+ else {
+ fprintf(stderr,"%s: PARSE ERROR: Disallowed character '%c' for field name \
+(e.g. no space between successive delimiters).\n",func,*(eq-j));
+ return ULM_PARSE_ERROR;
+ }
+ } /* for */
+
+ /* Replace delimiters and intervening whitespace by nul characters */
+ for (i=0; i<eqCnt; i++) this->raw[iArrayEQ[i]] = '\0';
+ for (i=0; i<spCnt; i++) this->raw[iArraySP[i]] = '\0';
+
+ this->num = eqCnt;
+
+ /* Debug dump of parsed fields */
+// for( i=0; i<eqCnt; i++ ) fprintf(stdout,"field[%d]: %s=%s\n",i,this->raw+this->names[i],this->raw+this->vals[i]);
+
+ return ULM_PARSE_OK;
+}
+
+/*
+ *---------------------------------------------------------------------------
+ * edg_wll_ULMisalphaext - test if the character is an ALPHAEXT as described in
+ * draft-abela-ulm-05
+ *---------------------------------------------------------------------------
+ */
+int edg_wll_ULMisalphaext( int c) {
+
+ return (isalnum(c) || (c == '.') || (c == '-') || c == '_');
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * edg_wll_ULMGetNameAt -- Get name at index.
+ *
+ * Calls:
+ *
+ * Algorithm: array lookup
+ *
+ *----------------------------------------------------------------------
+ */
+char *edg_wll_ULMGetNameAt( p_edg_wll_ULMFields this, int index )
+{
+ if ( index < 0 || index > this->num )
+ return NULL;
+ return (char *)&(this->raw[this->names[index]]);
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * edg_wll_ULMGetValueAt -- Get value at index
+ *
+ * Calls:
+ *
+ * Algorithm: array lookup
+ *
+ *----------------------------------------------------------------------
+ */
+char *edg_wll_ULMGetValueAt( p_edg_wll_ULMFields this, int index )
+{
+ if ( index < 0 || index > this->num )
+ return NULL;
+ return (char *)&(this->raw[this->vals[index]]);
+}
+
+/*
+ *---------------------------------------------------------------------------
+ * edg_wll_ULMDateToDouble -- Calculate date in sec. since 1/1/1970 from string.
+ * Algorithm borrowed from linux kernel source code,
+ * i.e. Linus Torvalds, who in turn credits it to Gauss.
+ *
+ * PRE: Input is properly formatted, non-null, need _not_ be null-terminated.
+ * IN : String in format YYYYMMDDHHmmss.uuuuuu
+ * YYYY = 4 digit year
+ * MM = 2 digit month (1..12)
+ * DD = 2 digit day of month (1..31)
+ * HH = 2 digit hour of day ( 0..23 )
+ * mm = 2 digit minute of hour ( 0..59 )
+ * ss = 2 digit second of minute ( 0..59 )
+ * uuuuuu= 1..6 digit microsecond of second ( 0..999999 )
+ * OUT: Number of seconds, and fraction accurate to at most microseconds,
+ * elapsed since 1/1/1970 (GMT).
+ *
+ * edg_wll_ULMDateToTimeval -- the same, except it returns timeval
+ *---------------------------------------------------------------------------
+ */
+double edg_wll_ULMDateToDouble( const char *s )
+{
+ unsigned int year, mon, day, hour, min, sec=0;
+ unsigned long usec=0L;
+
+ edg_wll_ULMSplitDate( s, &year, &mon, &day, &hour, &min, &sec, &usec );
+
+ if (0 >= (int) (mon -= 2)) { /* 1..12 -> 11,12,1..10 */
+ mon += 12; /* Puts Feb last since it has leap day */
+ year -= 1;
+ }
+ return (double)
+ ( ( ( (
+ (unsigned long)(year/4 - year/100 + year/400 + 367*mon/12 + day) +
+ year*365 - 719499
+ )*24 + hour /* now have hours */
+ )*60 + min /* now have minutes */
+ )*60 + sec /* seconds */
+ ) + (double)( usec / 1E6 ); /* microseconds */
+}
+
+void edg_wll_ULMDateToTimeval( const char *s, struct timeval *tv )
+{
+ unsigned int year, mon, day, hour, min, sec=0;
+ unsigned long usec=0L;
+
+ edg_wll_ULMSplitDate( s, &year, &mon, &day, &hour, &min, &sec, &usec );
+
+ if (0 >= (int) (mon -= 2)) { /* 1..12 -> 11,12,1..10 */
+ mon += 12; /* Puts Feb last since it has leap day */
+ year -= 1;
+ }
+ tv->tv_sec = (long)
+ ( ( ( (
+ (unsigned long)(year/4 - year/100 + year/400 + 367*mon/12 + day) +
+ year*365 - 719499
+ )*24 + hour /* now have hours */
+ )*60 + min /* now have minutes */
+ )*60 + sec /* seconds */
+ );
+ tv->tv_usec = usec; /* microseconds */
+}
+
+/*
+ *---------------------------------------------------------------------------
+ * edg_wll_ULMSplitDate -- Efficiently break date into parsed component parts.
+ *---------------------------------------------------------------------------
+ */
+#define DIG(x) ((int)((x)-'0'))
+void edg_wll_ULMSplitDate( const char *s,
+ unsigned int *year,
+ unsigned int *mon,
+ unsigned int *day,
+ unsigned int *hour,
+ unsigned int *min,
+ unsigned int *sec,
+ unsigned long *usec )
+{
+ *year = DIG(s[0]) * 1000 + DIG(s[1]) * 100 + DIG(s[2]) * 10 + DIG(s[3]);
+ *mon = DIG(s[4]) * 10 + DIG(s[5]);
+ *day = DIG(s[6]) * 10 + DIG(s[7]);
+ *hour = DIG(s[8]) * 10 + DIG(s[9]);
+ *min = DIG(s[10]) * 10 + DIG(s[11]);
+ *sec = DIG(s[12]) * 10 + DIG(s[13]);
+ if ( s[14] == '.' ) *usec = atol(s+15);
+}
+#undef DIG
+
+/*
+ *---------------------------------------------------------------------------
+ * edg_wll_ULMTimevalToDate -- Take a seconds, microseconds argument and convert it
+ * to a date string that edg_wll_ULMDateToDouble could parse.
+ *
+ * CALL: gmtime, strftime
+ *
+ * PRE : seconds, usec >= 0 , usec < 1000000 (checked)
+ * date string has DATE_STRING_LENGTH+1 bytes allocated (not checked)
+ * IN : seconds, useconds
+ * OUT : date string 'dstr'.
+ * RTRN: 0=OK, other=FAILURE
+ * POST: This is the inverse of edg_wll_ULMDateToDouble, i.e.
+ * edg_wll_ULMDateToDouble( edg_wll_ULMTimevalToDate( sec, usec ) ) = sec.usec
+ *---------------------------------------------------------------------------
+ */
+int edg_wll_ULMTimevalToDate( long sec, long usec, char *dstr )
+{
+ char *func = "edg_wll_ULMTimevalToDate";
+ struct tm *tp;
+ int len;
+
+ if ( sec < 0 || usec < 0 || usec > 999999 )
+ return 1;
+
+ tp = gmtime( (const time_t *) &sec );
+ if ( tp == NULL )
+ return 1;
+
+ len = strftime( dstr,
+ ULM_DATE_STRING_LENGTH+1-7,
+ "%Y%m%d%H%M%S",
+ tp );
+ if ( len != ULM_DATE_STRING_LENGTH-7 ) {
+ fprintf(stderr,"%s: bad strftime() return value: %d\n",func, len);
+ return 1;
+ }
+
+ sprintf( dstr + ULM_DATE_STRING_LENGTH-7, ".%06ld", usec );
+
+ return 0;
+}
+
--- /dev/null
+#ident "$Header$"
+
+#include <string.h>
+#include <expat.h>
+
+#include "glite/lb/trio.h"
+
+#include "xml_conversions.h"
+
+
+
+static const struct timeval null_timeval = {0,0};
+
+
+/************************************************************************/
+/* Context manipulation functions */
+
+
+void edg_wll_initXMLCtx(edg_wll_XML_ctx *c) {
+ c->ctx = NULL;
+ c->p = NULL;
+ c->message_body = NULL;
+ c->eventCode = EDG_WLL_EVENT_UNDEF;
+ c->position = 0;
+ c->position2 = 0;
+ c->max_index = -1;
+ c->row = 0;
+ c->row2 = 0;
+ c->level = 0;
+ memset(&(c->element), 0, sizeof(c->element));
+ c->char_buf = NULL;
+ c->char_buf_len = 0;
+ c->XML_tag = NULL;
+ c->XML_tag2 = NULL;
+ c->job_conditions = NULL;
+ c->event_conditions = NULL;
+ c->type = EDG_WLL_QUERY_TYPE_UNDEF;
+ c->flags = 0;
+ c->jobsOutGlobal = NULL;
+ c->eventsOutGlobal = NULL;
+ c->jobStatGlobal = NULL;
+ memset(&(c->jobStatSingleGlobal),0,sizeof(c->jobStatSingleGlobal));
+ c->strListGlobal = NULL;
+ c->intListGlobal = NULL;
+ c->indexToTag = NULL;
+ c->tagToIndex = NULL;
+ c->tagListGlobal = NULL;
+ c->stsListGlobal = NULL;
+ memset(&(c->purgeRequestGlobal),0,sizeof(c->purgeRequestGlobal));
+ memset(&(c->purgeResultGlobal),0,sizeof(c->purgeResultGlobal));
+ memset(&(c->dumpRequestGlobal),0,sizeof(c->dumpRequestGlobal));
+ memset(&(c->dumpResultGlobal),0,sizeof(c->dumpResultGlobal));
+ memset(&(c->loadRequestGlobal),0,sizeof(c->loadRequestGlobal));
+ memset(&(c->loadResultGlobal),0,sizeof(c->loadResultGlobal));
+ c->notifFunction = NULL;
+ c->notifClientAddress = NULL;
+ c->notifId = NULL;
+ c->notifChangeOp = EDG_WLL_NOTIF_NOOP;
+ c->notifValidity = -1;
+ c->attrsGlobal = NULL;
+ c->errCode = 0;
+ c->bound = 0;
+ c->errDesc = NULL;
+ c->stat_begin = 0;
+ c->jobQueryRec_begin = 0;
+ c->errtxt = NULL;
+ c->warntxt = NULL;
+}
+
+
+void edg_wll_freeXMLCtx(edg_wll_XML_ctx *c) {
+ if (c->char_buf) free(c->char_buf);
+ if (c->errtxt) free(c->errtxt);
+ if (c->warntxt) free(c->warntxt);
+ if (c->XML_tag) free(c->XML_tag);
+ if (c->XML_tag2) free(c->XML_tag2);
+}
+
+
+void edg_wll_freeBuf(edg_wll_XML_ctx *c) {
+ free(c->char_buf);
+ c->char_buf = NULL;
+ c->char_buf_len = 0;
+}
+
+
+
+/************************************************************************/
+/* type to XML conversion functions */
+
+
+/* edg_wll_add_string_to_XMLBody(&body, eventsOut[i].jobMatch.destination, "destination", NULL) */
+
+void edg_wll_add_string_to_XMLBody(char **body, const char *toAdd, const char *tag, const char *null)
+{
+ if ( toAdd != null ) {
+ char *newBody;
+
+ trio_asprintf(&newBody,"%s\t\t\t<%s>%|Xs</%s>\r\n", *body, tag, toAdd, tag);
+
+ free(*body);
+ *body = newBody;
+ }
+}
+
+void edg_wll_add_tagged_string_to_XMLBody(char **body, const char *toAdd, const char *tag,
+ const char *name, const char *tag2, const char *null)
+{
+ if ( toAdd != null ) {
+ char *newBody;
+
+ trio_asprintf(&newBody,"%s\t\t\t<%s %s=\"%|Xs\">%|Xs</%s>\r\n",
+ *body, tag, tag2, name, toAdd, tag);
+
+ free(*body);
+ *body = newBody;
+ }
+}
+
+/* edg_wll_add_int_to_XMLBody(&body, eventsOut[i].jobMatch.code, "code", 0) */
+
+void edg_wll_add_int_to_XMLBody(char **body, const int toAdd, const char *tag, const int null)
+{
+ if (toAdd != null) {
+ char *newBody;
+
+ trio_asprintf(&newBody,"%s\t\t\t<%s>%|Xd</%s>\r\n", *body, tag, toAdd, tag);
+
+ free(*body);
+ *body = newBody;
+ }
+}
+
+
+/* edg_wll_add_timeval_to_XMLBody(&body, eventsOut[i].any.tv, "timestamp", -1) */
+
+void edg_wll_add_timeval_to_XMLBody(char **body, struct timeval toAdd, const char *tag, const struct timeval null)
+{
+
+ if (toAdd.tv_sec != null.tv_sec || toAdd.tv_usec != null.tv_usec) {
+ char *newBody;
+
+ trio_asprintf(&newBody,"%s\t\t\t<%s>%ld.%06ld</%s>\r\n",
+ *body, tag, toAdd.tv_sec, toAdd.tv_usec, tag);
+
+ free(*body);
+ *body = newBody;
+ }
+}
+
+
+/* edg_wll_add_jobid_to_XMLBody(&body, eventsOut[i].any.jobId, "jobId", NULL) */
+
+void edg_wll_add_jobid_to_XMLBody(char **body, edg_wlc_JobId toAdd, const char *tag, const void *null)
+{
+ if (toAdd != (edg_wlc_JobId) null) {
+ char *newBody, *pom;
+
+ trio_asprintf(&newBody,"%s\t\t\t<%s>%|Xs</%s>\r\n",
+ *body, tag, pom = edg_wlc_JobIdUnparse(toAdd), tag);
+
+ free(*body);
+ free(pom);
+ *body = newBody;
+ }
+}
+
+
+void edg_wll_add_notifid_to_XMLBody(char **body, edg_wll_NotifId toAdd, const char *tag, const void *null)
+{
+ if (toAdd != (edg_wll_NotifId) null) {
+ char *newBody, *pom;
+
+ trio_asprintf(&newBody,"%s\t\t\t<%s>%|Xs</%s>\r\n",
+ *body, tag, pom = edg_wll_NotifIdUnparse(toAdd), tag);
+
+ free(*body);
+ free(pom);
+ *body = newBody;
+ }
+}
+
+
+/* edg_wll_add_edg_wll_JobStatCode_to_XMLBody(&body, eventsOut[i].any.jobId, "jobId", EDG_WLL_JOB_UNDEF) */
+
+void edg_wll_add_edg_wll_JobStatCode_to_XMLBody(char **body, edg_wll_JobStatCode toAdd, const char *tag, const edg_wll_JobStatCode null)
+{
+ if (toAdd != null) {
+ char *newBody, *pom;
+
+ trio_asprintf(&newBody,"%s\t\t\t<%s>%|Xs</%s>\r\n",
+ *body, tag, pom = edg_wll_StatToString(toAdd), tag);
+
+ free(*body);
+ free(pom);
+ *body = newBody;
+ }
+}
+
+void edg_wll_add_edg_wll_EventCode_to_XMLBody(char **body, edg_wll_EventCode toAdd, const char *tag, const edg_wll_EventCode null)
+{
+ char *newBody, *pom;
+
+ if (toAdd != null) {
+ trio_asprintf(&newBody,"%s\t\t\t<%s>%|Xs</%s>\r\n",
+ *body, tag, pom = edg_wll_EventToString(toAdd), tag);
+
+ free(*body);
+ free(pom);
+ *body = newBody;
+ }
+}
+
+
+void edg_wll_add_time_t_to_XMLBody(char **body, const time_t toAdd, const char *tag, const time_t null)
+{
+ if (toAdd != null) {
+ char *newBody;
+
+ trio_asprintf(&newBody,"%s\t\t\t<%s>%|Xld</%s>\r\n", *body, tag, toAdd, tag);
+
+ free(*body);
+ *body = newBody;
+ }
+}
+
+
+void edg_wll_add_tagged_time_t_to_XMLBody(char **body, const time_t toAdd, const char *tag,
+ const char *name, const char *tag2, const time_t null)
+{
+ if ( toAdd != null ) {
+ char *newBody;
+
+ trio_asprintf(&newBody,"%s\t\t\t<%s %s=\"%|Xs\">%|Xld</%s>\r\n",
+ *body, tag, tag2, name, toAdd, tag);
+
+ free(*body);
+ *body = newBody;
+ }
+}
+
+
+void edg_wll_add_uint16_t_to_XMLBody(char **body, const uint16_t toAdd, const char *tag, const uint16_t null)
+{
+ if (toAdd != null) {
+ char *newBody;
+
+ trio_asprintf(&newBody,"%s\t\t\t<%s>%|Xu</%s>\r\n", *body, tag, toAdd, tag);
+
+ free(*body);
+ *body = newBody;
+ }
+}
+
+
+void edg_wll_add_logsrc_to_XMLBody(char **body, const edg_wll_Source toAdd, const char *tag, const edg_wll_Source null)
+{
+ if (toAdd != null) {
+ char *newBody, *pom;
+
+ trio_asprintf(&newBody,"%s\t\t\t<%s>%|Xs</%s>\r\n",
+ *body, tag, pom = edg_wll_SourceToString(toAdd), tag);
+
+ free(*body);
+ free(pom);
+ *body = newBody;
+ }
+}
+
+void edg_wll_add_strlist_to_XMLBody(char **body, char * const *toAdd, const char *tag, const char *subTag, const char *indent, const char *null)
+{
+ char *pomA, *pomB, *newBody;
+ char **list = NULL;
+ int i = 0, len, tot_len = 0;
+ int *len_list = NULL;
+
+
+ if (!toAdd) return;
+
+ while (toAdd[i] != null) {
+ len = trio_asprintf(&pomA,"%s\t<%s>%|Xs</%s>\r\n",
+ indent,subTag,toAdd[i],subTag);
+
+ i++;
+ tot_len += len;
+
+ list = (char **) realloc(list, i * sizeof(*list));
+ list[i-1] = pomA;
+ pomA = NULL;
+ len_list = (int *) realloc(len_list, i * sizeof(*len_list));
+ len_list[i-1] = len;
+ }
+
+ /* list termination */
+ list = (char **) realloc(list, (i+1) * sizeof(*list));
+ list[i] = NULL;
+
+ /* glueing all list fields together & freeing the list */
+ pomA = (char *) malloc(tot_len * sizeof(char) + 1);
+ pomB = pomA;
+
+ i = 0;
+ while (list[i]) {
+ memcpy(pomB, list[i], len_list[i] );
+ pomB += len_list[i];
+
+ /* freeing the list */
+ free(list[i]);
+
+ i++;
+ }
+ *pomB = '\0';
+ free(list);
+ free(len_list);
+
+ asprintf(&newBody,"%s%s<%s>\r\n%s%s</%s>\r\n", *body, indent, tag, pomA, indent, tag);
+ free(*body);
+ free(pomA);
+ *body = newBody;
+}
+
+void edg_wll_add_intlist_to_XMLBody(char **body, const int *toAdd, const char *tag, char *(*indexToTag)(), const char *indent, const int from, const int to)
+{
+ char *pomA, *pomB, *newBody;
+ char **list = NULL;
+ int i, len, tot_len = 0;
+ int *len_list = NULL;
+
+
+ i = from;
+ while (i <= to) {
+ len = trio_asprintf(&pomA,"%s\t<%s>%|Xd</%s>\r\n",
+ indent, indexToTag(i-1),toAdd[i],indexToTag(i-1));
+
+ i++;
+ tot_len += len;
+
+ list = (char **) realloc(list, i * sizeof(*list));
+ list[i-1] = pomA;
+ pomA = NULL;
+ len_list = (int *) realloc(len_list, i * sizeof(*len_list));
+ len_list[i-1] = len;
+ }
+
+ /* list termination */
+ list = (char **) realloc(list, (i+1) * sizeof(*list));
+ list[i] = NULL;
+
+ /* glueing all list fields together & freeing the list */
+ pomA = (char *) malloc(tot_len * sizeof(char) + 1);
+ pomB = pomA;
+
+ i = from;
+ while (list[i]) {
+ memcpy(pomB, list[i], len_list[i] );
+ pomB += len_list[i];
+
+ /* freeing the list */
+ free(list[i]);
+
+ i++;
+ }
+ *pomB = '\0';
+ free(list);
+ free(len_list);
+
+ asprintf(&newBody,"%s%s<%s>\r\n%s%s</%s>\r\n", *body, indent, tag, pomA, indent, tag);
+ free(*body);
+ free(pomA);
+ *body = newBody;
+}
+
+
+void edg_wll_add_taglist_to_XMLBody(char **body, const edg_wll_TagValue *toAdd, const char *tag, const char *subTag, const char *subTag2, const char *indent, const char *null)
+{
+ char *pomA, *pomB, *newBody;
+ char **list = NULL;
+ int i = 0, len, tot_len = 0;
+ int *len_list = NULL;
+
+
+ while (toAdd && (toAdd[i].tag != null) ) {
+ len = trio_asprintf(&pomA,"%s\t<%s %s=\"%|Xs\">%|Xs</%s>\r\n",
+ indent,subTag,subTag2,toAdd[i].tag,toAdd[i].value,subTag);
+
+ i++;
+ tot_len += len;
+
+ list = (char **) realloc(list, i * sizeof(*list));
+ list[i-1] = pomA;
+ pomA = NULL;
+ len_list = (int *) realloc(len_list, i * sizeof(*len_list));
+ len_list[i-1] = len;
+ }
+
+ /* list termination */
+ list = (char **) realloc(list, (i+1) * sizeof(*list));
+ list[i] = NULL;
+
+ /* glueing all list fields together & freeing the list */
+ pomA = (char *) malloc(tot_len * sizeof(char) + 1);
+ pomB = pomA;
+
+ i = 0;
+ while (list[i]) {
+ memcpy(pomB, list[i], len_list[i] );
+ pomB += len_list[i];
+
+ /* freeing the list */
+ free(list[i]);
+
+ i++;
+ }
+ *pomB = '\0';
+ free(list);
+ free(len_list);
+
+ asprintf(&newBody,"%s%s<%s>\r\n%s%s</%s>\r\n", *body, indent, tag, pomA, indent, tag);
+ free(*body);
+ free(pomA);
+ *body = newBody;
+}
+
+
+void edg_wll_add_time_t_list_to_XMLBody(char **body, const time_t *toAdd, const char *tag, char *(*indexToTag)(), const char *indent, const int from, const int to)
+{
+ char *pomA, *pomB, *newBody;
+ char **list = NULL;
+ int i, len, tot_len = 0;
+ int *len_list = NULL;
+
+
+ i = from;
+ while (i < to) {
+ len = trio_asprintf(&pomA,"%s\t<%s>%|Xld</%s>\r\n",
+ indent, indexToTag(i),toAdd[i],indexToTag(i));
+
+ i++;
+ tot_len += len;
+
+ list = (char **) realloc(list, i * sizeof(*list));
+ list[i-1] = pomA;
+ pomA = NULL;
+ len_list = (int *) realloc(len_list, i * sizeof(*len_list));
+ len_list[i-1] = len;
+ }
+
+ /* list termination */
+ list = (char **) realloc(list, (i+1) * sizeof(*list));
+ list[i] = NULL;
+
+ /* glueing all list fields together & freeing the list */
+ pomA = (char *) malloc(tot_len * sizeof(char) + 1);
+ pomB = pomA;
+
+ i = 0;
+ while (list[i]) {
+ memcpy(pomB, list[i], len_list[i] );
+ pomB += len_list[i];
+
+ /* freeing the list */
+ free(list[i]);
+
+ i++;
+ }
+ *pomB = '\0';
+ free(list);
+ free(len_list);
+
+ asprintf(&newBody,"%s%s<%s>\r\n%s%s</%s>\r\n", *body, indent, tag, pomA, indent, tag);
+ free(*body);
+ free(pomA);
+ *body = newBody;
+}
+
+
+// void edg_wll_add_stslist_to_XMLBody(char **body, const edg_wll_JobStat *toAdd, const char *tag, const char *UNUSED_subTag, const int null)
+// in lbserver/lb_xml_parse.c.T
+
+/************************************************************************/
+/* string to type conversion functions */
+
+
+/* XMLCtx->eventsOutGlobal[XMLCtx->position].any.prog = edg_wll_from_string_to_string(XMLCtx); */
+char *edg_wll_from_string_to_string(edg_wll_XML_ctx *XMLCtx)
+{
+ return(XMLCtx->char_buf);
+}
+
+
+/* XMLCtx->eventsOutGlobal[XMLCtx->position].any.jobId = edg_wll_from_string_to_dgJobId(XMLCtx); */
+edg_wlc_JobId edg_wll_from_string_to_jobid(edg_wll_XML_ctx *XMLCtx)
+{
+ edg_wlc_JobId out;
+
+ edg_wlc_JobIdParse(XMLCtx->char_buf, &out);
+ edg_wll_freeBuf(XMLCtx);
+
+ return(out);
+}
+
+
+
+edg_wll_NotifId edg_wll_from_string_to_notifid(edg_wll_XML_ctx *XMLCtx)
+{
+ edg_wll_NotifId out;
+
+ edg_wll_NotifIdParse(XMLCtx->char_buf, &out);
+ edg_wll_freeBuf(XMLCtx);
+
+ return(out);
+}
+
+
+
+edg_wll_JobStatCode edg_wll_from_string_to_edg_wll_JobStatCode(edg_wll_XML_ctx *XMLCtx)
+{
+ edg_wll_JobStatCode out;
+
+ out = edg_wll_StringToStat(XMLCtx->char_buf);
+ edg_wll_freeBuf(XMLCtx);
+
+ return(out);
+}
+
+
+
+
+/* XMLCtx->eventsOutGlobal[XMLCtx->position].jobClear.clearReason =
+ edg_wll_from_string_to_int(XMLCtx); */
+int edg_wll_from_string_to_int(edg_wll_XML_ctx *XMLCtx)
+{
+ int out;
+
+ out = atoi(XMLCtx->char_buf);
+ edg_wll_freeBuf(XMLCtx);
+
+ return(out);
+}
+
+
+long edg_wll_from_string_to_long(edg_wll_XML_ctx *XMLCtx)
+{
+ long out;
+
+ out = atol(XMLCtx->char_buf);
+ edg_wll_freeBuf(XMLCtx);
+
+ return(out);
+}
+
+
+uint16_t edg_wll_from_string_to_uint16_t(edg_wll_XML_ctx *XMLCtx)
+{
+ return( (uint16_t) edg_wll_from_string_to_int(XMLCtx) );
+}
+
+
+struct timeval edg_wll_from_string_to_timeval(edg_wll_XML_ctx *XMLCtx)
+{
+ struct timeval out;
+ char *needle, *nil;
+
+ out.tv_sec = strtol(XMLCtx->char_buf, &needle, 10);
+ out.tv_usec = strtol(needle+1, &nil, 10);
+ edg_wll_freeBuf(XMLCtx);
+
+ return(out);
+}
+
+
+time_t edg_wll_from_string_to_time_t(edg_wll_XML_ctx *XMLCtx)
+{
+ return( (time_t) edg_wll_from_string_to_long(XMLCtx) );
+}
+
+
+edg_wll_Source edg_wll_from_string_to_logsrc(edg_wll_XML_ctx *XMLCtx)
+{
+ edg_wll_Source out = edg_wll_StringToSource(XMLCtx->char_buf);
+
+ edg_wll_freeBuf(XMLCtx);
+ return(out);
+}
+
+
+
+/************************************************************************/
+/* various conversion functions */
+
+
+char *edg_wll_stat_flags_to_string(int flags)
+{
+ char *cflags = NULL, *temp_cflags = NULL;
+
+
+ if (flags & EDG_WLL_STAT_CLASSADS) asprintf(&cflags,"%s","classadd");
+ if (flags & EDG_WLL_STAT_CHILDREN) {
+ if (cflags) {
+ asprintf(&temp_cflags,"%s+%s",cflags,"children");
+ free(cflags);
+ cflags=temp_cflags;
+ }
+ else asprintf(&cflags,"%s","children");
+ }
+ if (flags & EDG_WLL_STAT_CHILDSTAT) {
+ if (cflags) {
+ asprintf(&temp_cflags,"%s+%s",cflags,"childstat");
+ free(cflags);
+ cflags=temp_cflags;
+ }
+ else asprintf(&cflags,"%s","childstat");
+ }
+ if (flags & EDG_WLL_STAT_NO_JOBS) {
+ if (cflags) {
+ asprintf(&temp_cflags,"%s+%s",cflags,"no_jobs");
+ free(cflags);
+ cflags=temp_cflags;
+ }
+ else asprintf(&cflags,"%s","no_jobs");
+ }
+ if (flags & EDG_WLL_STAT_NO_STATES) {
+ if (cflags) {
+ asprintf(&temp_cflags,"%s+%s",cflags,"no_states");
+ free(cflags);
+ cflags=temp_cflags;
+ }
+ else asprintf(&cflags,"%s","no_states");
+ }
+
+ if (!cflags) cflags = strdup("");
+
+ return(cflags);
+}
+
+
+int edg_wll_string_to_stat_flags(char *cflags)
+{
+ int flags = 0;
+ char *sflag, *last;
+
+ if (cflags == NULL) return 0;
+
+ sflag = strtok_r(cflags, "+", &last);
+ while (sflag != NULL) {
+ if (!strcmp(sflag,"classadd")) flags = flags | EDG_WLL_STAT_CLASSADS;
+ if (!strcmp(sflag,"children")) flags = flags | EDG_WLL_STAT_CHILDREN;
+ if (!strcmp(sflag,"childstat")) flags = flags | EDG_WLL_STAT_CHILDSTAT;
+ if (!strcmp(sflag,"no_jobs")) flags = flags | EDG_WLL_STAT_NO_JOBS;
+ if (!strcmp(sflag,"no_states")) flags = flags | EDG_WLL_STAT_NO_STATES;
+ sflag = strtok_r(NULL, "+", &last);
+ }
+
+ return(flags);
+}
+
+
+char *edg_wll_purge_flags_to_string(int flags)
+{
+ char *cflags = NULL, *temp_cflags = NULL;
+
+
+ if (flags & EDG_WLL_PURGE_REALLY_PURGE) asprintf(&cflags,"%s","really_purge");
+ if (flags & EDG_WLL_PURGE_LIST_JOBS) {
+ if (cflags) {
+ asprintf(&temp_cflags,"%s+%s",cflags,"list_jobs");
+ free(cflags);
+ cflags=temp_cflags;
+ }
+ else asprintf(&cflags,"%s","list_jobs");
+ }
+ if (flags & EDG_WLL_PURGE_SERVER_DUMP) {
+ if (cflags) {
+ asprintf(&temp_cflags,"%s+%s",cflags,"server_dump");
+ free(cflags);
+ cflags=temp_cflags;
+ }
+ else asprintf(&cflags,"%s","server_dump");
+ }
+ if (flags & EDG_WLL_PURGE_CLIENT_DUMP) {
+ if (cflags) {
+ asprintf(&temp_cflags,"%s+%s",cflags,"client_dump");
+ free(cflags);
+ cflags=temp_cflags;
+ }
+ else asprintf(&cflags,"%s","client_dump");
+ }
+
+ if (!cflags) cflags = strdup("");
+
+ return(cflags);
+}
+
+
+int edg_wll_string_to_purge_flags(char *cflags)
+{
+ int flags = 0;
+ char *sflag, *last;
+
+ if (cflags == NULL) return 0;
+
+ sflag = strtok_r(cflags, "+", &last);
+ while (sflag != NULL) {
+ if (!strcmp(sflag,"really_purge")) flags = flags | EDG_WLL_PURGE_REALLY_PURGE;
+ if (!strcmp(sflag,"list_jobs")) flags = flags | EDG_WLL_PURGE_LIST_JOBS;
+ if (!strcmp(sflag,"server_dump")) flags = flags | EDG_WLL_PURGE_SERVER_DUMP;
+ if (!strcmp(sflag,"client_dump")) flags = flags | EDG_WLL_PURGE_CLIENT_DUMP;
+ sflag = strtok_r(NULL, "+", &last);
+ }
+
+ return(flags);
+}
+
+
+/* Functions for conversion of DUMP constants */
+
+static const char * const dumpConsts[] = {
+ "EDG_WLL_DUMP_NOW",
+ "EDG_WLL_DUMP_LAST_START",
+ "EDG_WLL_DUMP_LAST_END",
+};
+
+int edg_wll_StringToDumpConst(const char *name)
+
+{
+ int i;
+
+ for (i=0; i<sizeof(dumpConsts)/sizeof(dumpConsts[0]); i++)
+ if (strcasecmp(dumpConsts[i],name) == 0) return -(i+1);
+ return 1;
+}
+
+char *edg_wll_DumpConstToString(int dumpConst)
+{
+ if (dumpConst >= 0 || -(dumpConst) > sizeof(dumpConsts)/sizeof(dumpConsts[0])) return (char *) NULL;
+ return strdup(dumpConsts[-(dumpConst+1)]);
+}
+
+
+
+/* Functions for conversion of DONE CODE */
+
+static const char * const done_codeConsts[] = {
+ "DONE_CODE_OK",
+ "DONE_CODE_FAILED",
+ "DONE_CODE_CANCELLED",
+};
+
+int edg_wll_StringTodone_code(const char *name)
+
+{
+ int i;
+
+ for (i=0; i<sizeof(done_codeConsts)/sizeof(done_codeConsts[0]); i++)
+ if (strcasecmp(done_codeConsts[i],name) == 0) return i;
+ return 1;
+}
+
+char *edg_wll_done_codeToString(int done_codeConst)
+{
+ if (done_codeConst < 0 || (done_codeConst) > sizeof(done_codeConsts)/sizeof(done_codeConsts[0])) return (char *) NULL;
+ return strdup(done_codeConsts[done_codeConst]);
+}
+
+
+
+/* Functions for conversion of QUERY ATTRIBUTES */
+
+static const char * const query_attrConsts[] = {
+ "EDG_WLL_QUERY_ATTR_UNDEF",
+ "EDG_WLL_QUERY_ATTR_JOBID",
+ "EDG_WLL_QUERY_ATTR_OWNER",
+ "EDG_WLL_QUERY_ATTR_STATUS",
+ "EDG_WLL_QUERY_ATTR_LOCATION",
+ "EDG_WLL_QUERY_ATTR_DESTINATION",
+ "EDG_WLL_QUERY_ATTR_DONECODE",
+ "EDG_WLL_QUERY_ATTR_USERTAG",
+ "EDG_WLL_QUERY_ATTR_TIME",
+ "EDG_WLL_QUERY_ATTR_LEVEL",
+ "EDG_WLL_QUERY_ATTR_HOST",
+ "EDG_WLL_QUERY_ATTR_SOURCE",
+ "EDG_WLL_QUERY_ATTR_INSTANCE",
+ "EDG_WLL_QUERY_ATTR_EVENT_TYPE",
+ "EDG_WLL_QUERY_ATTR_CHKPT_TAG",
+ "EDG_WLL_QUERY_ATTR_RESUBMITTED",
+ "EDG_WLL_QUERY_ATTR_PARENT",
+ "EDG_WLL_QUERY_ATTR_EXITCODE",
+ "EDG_WLL_QUERY_ATTR__LAST",
+};
+
+edg_wll_QueryAttr edg_wll_StringToquery_attr(const char *name)
+
+{
+ int i;
+
+ for (i=0; i<sizeof(query_attrConsts)/sizeof(query_attrConsts[0]); i++)
+ if (strcasecmp(query_attrConsts[i],name) == 0) return (edg_wll_QueryAttr) i;
+ return EDG_WLL_QUERY_ATTR_UNDEF;
+}
+
+char *edg_wll_query_attrToString(edg_wll_QueryAttr query_attrConst)
+{
+ if (query_attrConst < 0 || (query_attrConst) > sizeof(query_attrConsts)/sizeof(query_attrConsts[0])) return (char *) NULL;
+ return strdup(query_attrConsts[(int) query_attrConst]);
+}
+
+
+
+/* Functions for conversion of NOTIFICATION CHANGE OPERATORS */
+
+static const char * const notifChangeOpConsts[] = {
+ "EDG_WLL_NOTIF_NOOP"
+ "EDG_WLL_NOTIF_REPLACE",
+ "EDG_WLL_NOTIF_ADD",
+ "EDG_WLL_NOTIF_REMOVE",
+};
+
+
+
+edg_wll_NotifChangeOp edg_wll_StringToNotifChangeOp(const char *name)
+{
+ int i;
+
+ for (i=0; i<sizeof(notifChangeOpConsts)/sizeof(notifChangeOpConsts[0]); i++)
+ if (strcasecmp(notifChangeOpConsts[i],name) == 0) return (edg_wll_NotifChangeOp) i;
+ return EDG_WLL_NOTIF_NOOP;
+}
+
+
+
+char *edg_wll_NotifChangeOpToString(edg_wll_NotifChangeOp notifChangeOpConst)
+{
+ if (notifChangeOpConst < 0 || (notifChangeOpConst) > sizeof(notifChangeOpConsts)/sizeof(notifChangeOpConsts[0])) return (char *) NULL;
+ return strdup(notifChangeOpConsts[(int) notifChangeOpConst]);
+}
--- /dev/null
+#ident "$Header$"
+
+#include <stdio.h>
+#include <ctype.h>
+#include <string.h>
+#include <assert.h>
+
+#include <expat.h> // Expat header file
+
+#include "globus_config.h"
+#include "glite/wms/thirdparty/globus_ssl_utils/sslutils.h"
+
+#include "glite/lb/trio.h"
+#include "glite/lb/producer.h"
+#include "glite/wms/jobid/cjobid.h"
+
+#include "escape.h"
+#include "context-int.h"
+#include "xml_parse.h"
+#include "xml_conversions.h"
+
+
+#ifdef __GNUC__
+#define UNUSED_VAR __attribute__((unused))
+#else
+#define UNUSED_VAR
+#endif
+
+#define QUERY_EVENTS_REQUEST_BEGIN "<edg_wll_QueryEventsRequest"
+#define QUERY_EVENTS_REQUEST_END "\t</and>\r\n</edg_wll_QueryEventsRequest>"
+#define QUERY_EVENTS_OREC_BEGIN "\t\t<orEventConditions>\r\n"
+#define QUERY_EVENTS_OREC_END "\t\t</orEventConditions>\r\n"
+#define QUERY_EVENTS_ORJC_BEGIN "\t\t<orJobConditions>\r\n"
+#define QUERY_EVENTS_ORJC_END "\t\t</orJobConditions>\r\n"
+#define QUERY_JOBS_REQUEST_BEGIN "<edg_wll_QueryJobsRequest"
+#define QUERY_JOBS_REQUEST_END "\t</and>\r\n</edg_wll_QueryJobsRequest>"
+#define QUERY_JOBS_OR_BEGIN "\t\t<orJobConditions>\r\n"
+#define QUERY_JOBS_OR_END "\t\t</orJobConditions>\r\n"
+#define PURGE_REQUEST_BEGIN "<edg_wll_PurgeRequest>\r\n"
+#define PURGE_REQUEST_END "</edg_wll_PurgeRequest>\r\n"
+#define DUMP_REQUEST_BEGIN "<edg_wll_DumpRequest>\r\n"
+#define DUMP_REQUEST_END "</edg_wll_DumpRequest>\r\n"
+#define LOAD_REQUEST_BEGIN "<edg_wll_LoadRequest>\r\n"
+#define LOAD_REQUEST_END "</edg_wll_LoadRequest>\r\n"
+#define INDEXED_ATTRS_REQUEST_BEGIN "<edg_wll_IndexedAttrsReguest>\r\n"
+#define INDEXED_ATTRS_REQUEST_END "</edg_wll_IndexedAttrsReguest>\r\n"
+#define NOTIF_REQUEST_BEGIN "<edg_wll_NotifRequest"
+#define NOTIF_REQUEST_END "</edg_wll_NotifRequest>\r\n"
+
+
+/* lists of accepted tags */
+static const char * const jobStatTags[] = {
+@@@{
+ selectType $status '_common_';
+ for (getFieldsOrdered $status) {
+ gen "\t\"$_\",\n";
+ }
+@@@}
+ NULL
+};
+
+
+@@@{
+ gen "static const char * const eventJobCommon\[] = {";
+ selectType $event '_common_';
+ for (getFieldsOrdered $event) {
+ my $f = selectField $event $_;
+ my $fn = $f->{name};
+ gen "\"$fn\", ";
+ }
+ gen "NULL };\n";
+@@@}
+@@@{
+ for my $t (sort { $event->{order}->{$a} <=> $event->{order}->{$b} }
+ $event->getTypes) {
+ gen "static const char * const event$t\[] = {";
+ selectType $event $t;
+ for (getFieldsOrdered $event) {
+ my $f = selectField $event $_;
+ my $fn = $f->{name};
+ gen "\"$fn\", "
+ }
+ gen "NULL };\n";
+ }
+@@@}
+
+
+
+static const char * const * const eventTags[] = {
+ eventJobCommon,
+@@@{
+ for my $t (sort { $event->{order}->{$a} <=> $event->{order}->{$b} }
+ $event->getTypes) {
+ gen "\tevent$t,\n";
+ }
+ gen "\tNULL\n};\n";
+@@@}
+
+
+
+/* used when error unrecoverable*/
+#define unexpError() {\
+ char *e;\
+\
+ if (XMLCtx->errtxt) {\
+ asprintf(&e,"%s\nunexpected <%s> at line %d",XMLCtx->errtxt,\
+ XMLCtx->element,XML_GetCurrentLineNumber(XMLCtx->p));\
+ free(XMLCtx->errtxt);\
+ } else asprintf(&e,"unexpected <%s> at line %d",\
+ XMLCtx->element,XML_GetCurrentLineNumber(XMLCtx->p));\
+ XMLCtx->errtxt = e;\
+}
+
+
+
+static void emptyCall(void){
+}
+
+/* used when error recoverable */
+// XXX quadratic complexity - problematic when lots of errors in long outputs (10.000's)
+#define unexpWarning() {\
+ char *e;\
+\
+emptyCall(); \
+ if (XMLCtx->warntxt) {\
+ asprintf(&e,"%s\nunexpected <%s> at line %d",XMLCtx->warntxt,\
+ XMLCtx->element,XML_GetCurrentLineNumber(XMLCtx->p));\
+ free(XMLCtx->warntxt);\
+ } else asprintf(&e,"unexpected <%s> at line %d",\
+ XMLCtx->element,XML_GetCurrentLineNumber(XMLCtx->p));\
+ XMLCtx->warntxt = e;\
+}
+
+
+
+
+static void startQueryJobs(void *data, const char *el, const char **attr)
+{
+ edg_wll_XML_ctx *XMLCtx = data;
+
+
+ if (XMLCtx->char_buf) edg_wll_freeBuf(XMLCtx);
+
+ strcpy(XMLCtx->element, el);
+
+ switch (XMLCtx->level) {
+ case 0 : if (strcmp("edg_wll_QueryJobsResult", el)) { unexpError() break;}
+ if (attr[0] && attr[1] && attr[2] && attr[3]) {
+ if (strcmp(attr[0],"code")) { unexpError() break;}
+ else XMLCtx->errCode = atoi(attr[1]);
+
+ if (strcmp(attr[2],"desc")) { unexpError() break;}
+ else XMLCtx->errDesc = strdup(attr[3]);
+ }
+ break;
+
+ case 1 : if (strcmp("edg_wll_Job", el)) unexpError()
+ break;
+
+ case 2 : if (!strcmp("jobId", el)) {
+ /* allocates space only for pointers to structures edg_wlc_jobid_t */
+ /* space for structures allocate characterUserJobs */
+ XMLCtx->jobsOutGlobal = realloc(XMLCtx->jobsOutGlobal,
+ (XMLCtx->position+1)*sizeof(*XMLCtx->jobsOutGlobal));
+ if (!XMLCtx->jobsOutGlobal) { edg_wll_SetError(XMLCtx->ctx, ENOMEM, NULL); unexpError() return; }
+ XMLCtx->jobsOutGlobal[XMLCtx->position] = NULL;
+ }
+ else if (!strcmp("jobStat", el)) {
+ XMLCtx->stat_begin = XML_GetCurrentByteIndex(XMLCtx->p);
+ XMLCtx->jobStatGlobal = (edg_wll_JobStat *) realloc(XMLCtx->jobStatGlobal,
+ (XMLCtx->position2+1)*sizeof(*XMLCtx->jobStatGlobal));
+
+ }
+ else unexpWarning()
+ break;
+
+ // XXX ?? this may be usefull with status
+ case 3 : /* fall through */
+ case 4 : /* do not check xml tags, try to be faul-tolerant */
+ /* if tag not found during unparsing, xmlMalformed flag is set */
+ break;
+
+ default: if (!XMLCtx->stat_begin) unexpWarning()
+ break;
+ }
+
+ XMLCtx->level++;
+}
+
+
+
+static void startQueryEvents(void *data, const char *el, const char **attr)
+{
+ edg_wll_XML_ctx *XMLCtx = data;
+
+
+ if (XMLCtx->char_buf) edg_wll_freeBuf(XMLCtx);
+
+ strcpy(XMLCtx->element, el);
+
+ switch (XMLCtx->level) {
+ case 0 : if (strcmp("edg_wll_QueryEventsResult", el)) { unexpError() break;}
+ if (attr[0] && attr[1] && attr[2] && attr[3]) {
+ if (strcmp(attr[0],"code")) { unexpError() break;}
+ else XMLCtx->errCode = atoi(attr[1]);
+
+ if (strcmp(attr[2],"desc")) { unexpError() break;}
+ else XMLCtx->errDesc = strdup(attr[3]);
+ }
+
+ break;
+
+ case 1 : if (strcmp("edg_wll_Event", el)) unexpError()
+ else {
+ XMLCtx->position++;
+
+ if (!attr[0] || !attr[1]) { unexpError() break;}
+ if (strcmp(attr[0],"name")) { unexpError() break;}
+ if ( (XMLCtx->eventCode = edg_wll_StringToEvent((char *) attr[1]))
+ == EDG_WLL_EVENT_UNDEF ) { unexpError() break;}
+ XMLCtx->eventsOutGlobal = realloc(XMLCtx->eventsOutGlobal,
+ (XMLCtx->position+1)*sizeof(*XMLCtx->eventsOutGlobal));
+ if (!XMLCtx->eventsOutGlobal) { edg_wll_SetError(XMLCtx->ctx, ENOMEM, NULL); unexpError() return; }
+ memset(&(XMLCtx->eventsOutGlobal)[XMLCtx->position],0,sizeof(*XMLCtx->eventsOutGlobal));
+ XMLCtx->eventsOutGlobal[XMLCtx->position].any.type = XMLCtx->eventCode;
+ }
+ break;
+
+ case 2 : /* do not check xml tags, try to be faul-tolerant */
+ /* if tag not found during unparsing, xmlMalformed flag is set */
+ break;
+
+ default: unexpWarning()
+ break;
+ }
+
+ XMLCtx->level++;
+}
+
+
+
+
+static void startUserJobs(void *data, const char *el, const char **attr UNUSED_VAR)
+{
+ edg_wll_XML_ctx *XMLCtx = data;
+
+
+ if (XMLCtx->char_buf) edg_wll_freeBuf(XMLCtx);
+
+ strcpy(XMLCtx->element, el);
+
+ switch (XMLCtx->level) {
+ case 0 : if (strcmp("edg_wll_UserJobs", el)) { unexpError() break;}
+ if (attr[0] && attr[1] && attr[2] && attr[3]) {
+ if (strcmp(attr[0],"code")) { unexpError() break;}
+ else XMLCtx->errCode = atoi(attr[1]);
+
+ if (strcmp(attr[2],"desc")) { unexpError() break;}
+ else XMLCtx->errDesc = strdup(attr[3]);
+ }
+ break;
+
+ case 1 : if (strcmp("jobId", el)) unexpError()
+ else {
+ /* allocates space only for pointers to structures edg_wlc_jobid_t */
+ /* space for structures allocate endUserJobs */
+ XMLCtx->jobsOutGlobal = realloc(XMLCtx->jobsOutGlobal,
+ (XMLCtx->position+1)*sizeof(XMLCtx->jobsOutGlobal));
+ if (!XMLCtx->jobsOutGlobal) { edg_wll_SetError(XMLCtx->ctx, ENOMEM, NULL); unexpError() return; }
+ XMLCtx->jobsOutGlobal[XMLCtx->position] = NULL;
+ }
+ break;
+
+
+ default: unexpWarning()
+ break;
+ }
+
+ XMLCtx->level++;
+}
+
+
+
+static void startJobStatus(void *data, const char *el, const char **attr)
+{
+ edg_wll_XML_ctx *XMLCtx = data;
+ edg_wll_JobStatCode statusCode; /* code of status in process */
+
+
+ if (XMLCtx->char_buf) edg_wll_freeBuf(XMLCtx);
+
+ strcpy(XMLCtx->element, el);
+
+ switch (XMLCtx->level) {
+ case 0 : if (strcmp("jobStat", el)) { unexpError() break;}
+ if (!attr[0] || !attr[1]) { unexpError() break;}
+ if (strcmp(attr[0],"name")) { unexpError() break;}
+
+ if ( (statusCode = edg_wll_StringToStat(attr[1]))
+ == (edg_wll_JobStatCode)-1 )
+ /* status unknown, but try to get as much as possible */
+ unexpWarning()
+ else {
+ if (edg_wll_InitStatus(&XMLCtx->jobStatSingleGlobal))
+ { edg_wll_SetError(XMLCtx->ctx, ENOMEM, NULL); unexpError() return; }
+ XMLCtx->jobStatSingleGlobal.state = statusCode;
+ }
+
+ if (attr[2] && attr[3] && attr[4] && attr[5]) {
+ if (strcmp(attr[2],"code")) { unexpError() break;}
+ else XMLCtx->errCode = atoi(attr[3]);
+
+ if (strcmp(attr[4],"desc")) { unexpError() break;}
+ else XMLCtx->errDesc = strdup(attr[5]);
+ }
+ break;
+
+ case 1 : if (!strcmp("user_tags", el) || !strcmp("user_values", el)
+ || !strcmp("children_hist", el) || !strcmp("stateEnterTimes", el)
+ || !strcmp("children_states", el) || !strcmp("children", el)) {
+ XMLCtx->stat_begin = XML_GetCurrentByteIndex(XMLCtx->p);
+ }
+ break;
+
+ case 2 : /* fall through */
+ case 3 : /* fall through */
+ case 4 : /* do not check xml tags, try to be faul-tolerant */
+ /* if tag not found during unparsing, xmlMalformed flag is set */
+ break;
+
+
+ default: unexpWarning()
+ break;
+ }
+
+ XMLCtx->level++;
+}
+
+
+static void startStrList(void *data, const char *el, const char **attr)
+{
+ edg_wll_XML_ctx *XMLCtx = data;
+
+
+ if (XMLCtx->char_buf) edg_wll_freeBuf(XMLCtx);
+
+ strcpy(XMLCtx->element, el);
+
+ switch (XMLCtx->level) {
+ case 0 : if (strcmp(XMLCtx->XML_tag, el)) unexpError()
+ break;
+
+ case 1 : if (!strcmp(XMLCtx->XML_tag2, el)) {
+ XMLCtx->strListGlobal = realloc(XMLCtx->strListGlobal,
+ (XMLCtx->position+1)*sizeof(*XMLCtx->strListGlobal));
+ if (!XMLCtx->strListGlobal) { edg_wll_SetError(XMLCtx->ctx, ENOMEM, NULL); unexpError() return; }
+ XMLCtx->strListGlobal[XMLCtx->position] = NULL;
+
+ }
+ break;
+
+ default: unexpWarning()
+ break;
+ }
+
+ XMLCtx->level++;
+}
+
+
+
+static void startIntList(void *data, const char *el, const char **attr)
+{
+ edg_wll_XML_ctx *XMLCtx = data;
+ int index = 0;
+
+
+ if (XMLCtx->char_buf) edg_wll_freeBuf(XMLCtx);
+
+ strcpy(XMLCtx->element, el);
+
+ switch (XMLCtx->level) {
+ case 0 : if (strcmp(XMLCtx->XML_tag, el)) unexpError()
+ break;
+
+ case 1 : if ( (index = XMLCtx->tagToIndex(el)) >= 0 ) {
+ if (index > XMLCtx->max_index) {
+ XMLCtx->max_index = index;
+ /* leave zeros' possition for array length */
+ XMLCtx->intListGlobal = realloc(XMLCtx->intListGlobal,
+ (XMLCtx->max_index+2)*sizeof(*XMLCtx->intListGlobal));
+ if (!XMLCtx->intListGlobal) {edg_wll_SetError(XMLCtx->ctx, ENOMEM, NULL); unexpError() return; }
+ XMLCtx->intListGlobal[XMLCtx->max_index+1] = 0;
+ }
+
+ }
+ break;
+
+ default: unexpWarning()
+ break;
+ }
+
+ XMLCtx->level++;
+}
+
+
+static void startTagList(void *data, const char *el, const char **attr)
+{
+ edg_wll_XML_ctx *XMLCtx = data;
+
+
+ if (XMLCtx->char_buf) edg_wll_freeBuf(XMLCtx);
+
+ strcpy(XMLCtx->element, el);
+
+ switch (XMLCtx->level) {
+ case 0 : if (strcmp(XMLCtx->XML_tag, el)) unexpError()
+ break;
+
+ case 1 : if (!attr[0] || !attr[1]) { unexpError() break;}
+ if (strcmp(attr[0],"name")) { unexpError() break;}
+
+ if (!strcmp(XMLCtx->XML_tag2, el)) {
+ XMLCtx->tagListGlobal = realloc(XMLCtx->tagListGlobal,
+ (XMLCtx->position+1)*sizeof(*XMLCtx->tagListGlobal));
+ if (!XMLCtx->tagListGlobal) { edg_wll_SetError(XMLCtx->ctx, ENOMEM, NULL); unexpError() return; }
+ XMLCtx->tagListGlobal[XMLCtx->position].tag = strdup(attr[1]);
+ XMLCtx->stat_begin = XML_GetCurrentByteIndex(XMLCtx->p);
+ }
+ break;
+
+ default: unexpWarning()
+ break;
+ }
+
+ XMLCtx->level++;
+}
+
+
+static void startStsList(void *data, const char *el, const char **attr)
+{
+ edg_wll_XML_ctx *XMLCtx = data;
+
+
+ if (XMLCtx->char_buf) edg_wll_freeBuf(XMLCtx);
+
+ strcpy(XMLCtx->element, el);
+
+ switch (XMLCtx->level) {
+ case 0 : if (strcmp(XMLCtx->XML_tag, el)) unexpError()
+ break;
+
+ case 1 : if (!strcmp(XMLCtx->XML_tag2, el)) {
+ XMLCtx->stsListGlobal = realloc(XMLCtx->stsListGlobal,
+ (XMLCtx->position+1)*sizeof(*XMLCtx->stsListGlobal));
+ if (!XMLCtx->stsListGlobal) { edg_wll_SetError(XMLCtx->ctx, ENOMEM, NULL); unexpError() return; }
+ // edg_wll_InitStatus(&XMLCtx->stsListGlobal[XMLCtx->position]);
+ // initialized in startJobStatus();
+
+ XMLCtx->stat_begin = XML_GetCurrentByteIndex(XMLCtx->p);
+ }
+ break;
+
+ case 2 : /* fall through */
+ case 3 : /* fall through */
+ case 4 : /* fall through */
+ case 5 : /* do not check xml tags ut to depth 5 */
+ /* will be checked later */
+ break;
+
+ default: unexpWarning()
+ break;
+ }
+
+ XMLCtx->level++;
+}
+
+
+
+static void startPurgeResult(void *data, const char *el, const char **attr)
+{
+ edg_wll_XML_ctx *XMLCtx = data;
+ int i;
+
+
+ strcpy(XMLCtx->element, el);
+
+ switch (XMLCtx->level) {
+ case 0: if (strcasecmp(el,"edg_wll_PurgeResult")) { unexpError() break;}
+ for ( i = 0; attr[i] && attr[i+1]; i += 2 ) {
+ if (!strcmp(attr[i],"code"))
+ XMLCtx->errCode = atoi(attr[i+1]);
+ else if (!strcmp(attr[i],"desc"))
+ XMLCtx->errDesc = strdup(attr[i+1]);
+ else { unexpError() }
+ }
+ break;
+ case 1: if (strcasecmp(el,"jobs") && strcasecmp(el,"server_file")) unexpWarning()
+ break;
+ case 2: if (!strcasecmp(el,"jobId")) {
+ XMLCtx->purgeResultGlobal.jobs = realloc(XMLCtx->purgeResultGlobal.jobs,
+ (XMLCtx->position+2) * sizeof(XMLCtx->purgeResultGlobal.jobs));
+
+ if (!XMLCtx->purgeResultGlobal.jobs) {
+ edg_wll_SetError(XMLCtx->ctx, ENOMEM, NULL);
+ unexpError() return;
+ }
+ XMLCtx->purgeResultGlobal.jobs[XMLCtx->position+1] = NULL;
+ }
+ else
+ unexpWarning()
+ break;
+ default: unexpWarning()
+ break;
+ }
+ XMLCtx->level++;
+}
+
+
+
+static void startDumpResult(void *data, const char *el, const char **attr)
+{
+ edg_wll_XML_ctx *XMLCtx = data;
+ int i;
+
+
+ strcpy(XMLCtx->element, el);
+
+ switch (XMLCtx->level) {
+ case 0: if (strcasecmp(el,"edg_wll_DumpResult")) { unexpError() break;}
+ for ( i = 0; attr[i] && attr[i+1]; i += 2 ) {
+ if (!strcmp(attr[i],"code"))
+ XMLCtx->errCode = atoi(attr[i+1]);
+ else if (!strcmp(attr[i],"desc"))
+ XMLCtx->errDesc = strdup(attr[i+1]);
+ else { unexpError() }
+ }
+ break;
+ case 1: if (strcasecmp(el,"from") && strcasecmp(el,"to")
+ && strcasecmp(el,"server_file")) unexpWarning()
+ break;
+ default: unexpWarning()
+ break;
+ }
+ XMLCtx->level++;
+}
+
+
+
+static void startLoadResult(void *data, const char *el, const char **attr)
+{
+ edg_wll_XML_ctx *XMLCtx = data;
+ int i;
+
+
+ strcpy(XMLCtx->element, el);
+
+ switch (XMLCtx->level) {
+ case 0: if (strcasecmp(el,"edg_wll_LoadResult")) { unexpError() break;}
+ for ( i = 0; attr[i] && attr[i+1]; i += 2 ) {
+ if (!strcmp(attr[i],"code"))
+ XMLCtx->errCode = atoi(attr[i+1]);
+ else if (!strcmp(attr[i],"desc"))
+ XMLCtx->errDesc = strdup(attr[i+1]);
+ else { unexpError() }
+ }
+ break;
+ case 1: if (strcasecmp(el,"from") && strcasecmp(el,"to")
+ && strcasecmp(el,"server_file")) unexpWarning()
+ break;
+ default: unexpWarning()
+ break;
+ }
+ XMLCtx->level++;
+}
+
+
+
+static void startIndexedAttrs(void *data, const char *el, const char **attr)
+{
+ edg_wll_XML_ctx *XMLCtx = data;
+ int i;
+
+
+ strcpy(XMLCtx->element, el);
+
+ switch (XMLCtx->level) {
+ case 0: if (strcasecmp(el,"edg_wll_GetIndexedAttributesResult")) { unexpError() break;}
+ for ( i = 0; attr[i] && attr[i+1]; i += 2 ) {
+ if (!strcmp(attr[i],"code"))
+ XMLCtx->errCode = atoi(attr[i+1]);
+ else if (!strcmp(attr[i],"desc"))
+ XMLCtx->errDesc = strdup(attr[i+1]);
+ else { unexpError() }
+ }
+ break;
+ case 1: if (!strcasecmp(el,"index")) {
+ XMLCtx->attrsGlobal = realloc(XMLCtx->attrsGlobal,
+ (XMLCtx->position+2)*sizeof(*XMLCtx->attrsGlobal));
+ if (!XMLCtx->attrsGlobal) {
+ edg_wll_SetError(XMLCtx->ctx, ENOMEM, NULL);
+ unexpError()
+ return;
+ }
+ XMLCtx->attrsGlobal[XMLCtx->position] = NULL;
+ XMLCtx->attrsGlobal[XMLCtx->position+1] = NULL;
+ }
+ else
+ unexpWarning()
+ break;
+ case 2: if (!strcasecmp(el,"QueryRec")) {
+ XMLCtx->attrsGlobal[XMLCtx->position] =
+ realloc(XMLCtx->attrsGlobal[XMLCtx->position],
+ (XMLCtx->position2+2)*sizeof(**XMLCtx->attrsGlobal));
+ if (!XMLCtx->attrsGlobal[XMLCtx->position]) {
+ edg_wll_SetError(XMLCtx->ctx, ENOMEM, NULL);
+ unexpError()
+ return;
+ }
+ memset(&(XMLCtx->attrsGlobal[XMLCtx->position][XMLCtx->position2]), 0,
+ 2*sizeof(**XMLCtx->attrsGlobal));
+ }
+ else
+ unexpWarning()
+ break;
+ case 3: if (strcasecmp(el,"attribute") && strcasecmp(el,"state") &&
+ strcasecmp(el,"name")) unexpWarning()
+ break;
+ default: unexpWarning()
+ break;
+ }
+ XMLCtx->level++;
+}
+
+
+
+static void startNotifResult(void *data, const char *el, const char **attr)
+{
+ edg_wll_XML_ctx *XMLCtx = data;
+ int i;
+
+
+ strcpy(XMLCtx->element, el);
+
+ switch (XMLCtx->level) {
+ case 0: if (strcasecmp(el,"edg_wll_NotifResult")) { unexpError() break;}
+ for ( i = 0; attr[i] && attr[i+1]; i += 2 ) {
+ if (!strcmp(attr[i],"code"))
+ XMLCtx->errCode = atoi(attr[i+1]);
+ else if (!strcmp(attr[i],"desc"))
+ XMLCtx->errDesc = strdup(attr[i+1]);
+ else { unexpError() }
+ }
+ break;
+ case 1: if (strcasecmp(el,"validity")) unexpWarning()
+ break;
+ default: unexpWarning()
+ break;
+ }
+ XMLCtx->level++;
+}
+
+
+
+static void char_handler(void *data, const char *s, int len)
+{
+ edg_wll_XML_ctx *XMLCtx = data;
+ int i, found = -1, temp_len1;
+ char *temp_s, *temp_s1;
+
+
+ /* if date are only spaces, t\, \r, \n ... don't bother with them */
+ for (i=0; i<len; i++)
+ if (!isspace(s[i])) { found = i; break; }
+ if (found == -1) return;
+
+ temp_s = malloc((len+1) * sizeof(char));
+
+ /* otherwise use them */
+ memcpy(temp_s,s,len);
+ temp_s[len] = 0;
+ temp_s1 = edg_wll_UnescapeXML((const char *) temp_s);
+ temp_len1 = strlen(temp_s1);
+
+ if (XMLCtx->char_buf_len)
+ XMLCtx->char_buf = realloc(XMLCtx->char_buf,XMLCtx->char_buf_len+temp_len1 + 1);
+ else
+ XMLCtx->char_buf = (char *) malloc(temp_len1 + 1);
+
+ memcpy(XMLCtx->char_buf+XMLCtx->char_buf_len,temp_s1,temp_len1 + 1);
+ XMLCtx->char_buf_len += temp_len1;
+ free(temp_s1);
+ free(temp_s);
+}
+
+
+
+static void endQueryJobs(void *data, const char *el)
+{
+ edg_wll_XML_ctx *XMLCtx = data;
+
+
+ switch (XMLCtx->level) {
+ case 3 :
+ if (!strcmp(XMLCtx->element,"jobId")) {
+ XMLCtx->jobsOutGlobal[XMLCtx->position] =
+ edg_wll_from_string_to_jobid(XMLCtx);
+ XMLCtx->position++;
+ }
+ else if (!strcmp(el,"jobStat")) {
+ long len = (XML_GetCurrentByteIndex(XMLCtx->p) + XML_GetCurrentByteCount(XMLCtx->p))
+ - XMLCtx->stat_begin;
+
+ edg_wll_ParseJobStat(XMLCtx->ctx, XMLCtx->message_body + XMLCtx->stat_begin, len,
+ &XMLCtx->jobStatGlobal[XMLCtx->position2]);
+ XMLCtx->position2++;
+ XMLCtx->stat_begin = 0;
+ }
+ else {
+ /* tag was not found -> either missing in previous code or unknown */
+ unexpWarning()
+ edg_wll_freeBuf(XMLCtx);
+ }
+ break;
+ default:
+ if (XMLCtx->char_buf) {
+// unexpWarning()
+ edg_wll_freeBuf(XMLCtx);
+ }
+ break;
+ }
+
+ XMLCtx->char_buf = NULL;
+ XMLCtx->char_buf_len = 0;
+ memset(&(XMLCtx->element), 0, sizeof(XMLCtx->element));
+ XMLCtx->level--;
+}
+
+
+static void endQueryEvents(void *data, const char *el UNUSED_VAR)
+{
+ edg_wll_XML_ctx *XMLCtx = data;
+
+
+ switch (XMLCtx->level) {
+ case 3:
+@@@{
+ my $i = 1;
+ my $bi = "\t ";
+ for my $t (sort {$a cmp $b} getAllFields $event) {
+ if ($i == 1)
+ { gen "$bi if (!strcmp(XMLCtx->element,\"$t\"))\n"; }
+ else
+ { gen "$bi else if (!strcmp(XMLCtx->element,\"$t\"))\n"; }
+ $i++;
+ my @fo = sort $event->getFieldOccurence($t);
+ if ($#fo == 0) {
+ selectType $event $fo[0];
+ my $f = selectField $event $t;
+ my $ft = $f->{type};
+ $fo[0] = $fo[0] eq '_common_' ? 'any' : lcfirst $fo[0];
+ gen "$bi XMLCtx->eventsOutGlobal[XMLCtx->position].$fo[0].$t =\n";
+ gen "$bi \tedg_wll_from_string_to_$ft(XMLCtx);\n";
+ }
+ else {
+ gen "\t switch (XMLCtx->eventsOutGlobal[XMLCtx->position].any.type) {\n";
+ for (@fo) {
+ selectType $event $_;
+ my $f = selectField $event $t;
+ my $ft = $f->{type};
+ $t = 'any' if $_ eq '_common_';
+ my $u = uc $_;
+ $_ = lcfirst $_;
+ gen "$bi case EDG_WLL_EVENT_$u :\n";
+ gen "$bi \t XMLCtx->eventsOutGlobal[XMLCtx->position].$_.$t =\n";
+ gen "$bi \t edg_wll_from_string_to_$ft(XMLCtx);\n";
+ gen "$bi \t break;\n";
+
+ }
+ gen "$bi default : { unexpWarning() edg_wll_freeBuf(XMLCtx); } \n";
+ gen "$bi }\n";
+ }
+ }
+@@@}
+
+ else {
+ /* tag was not found -> either missing in previous code or unknown */
+ unexpWarning()
+ edg_wll_freeBuf(XMLCtx);
+ }
+ break;
+ default:
+ if (XMLCtx->char_buf) {
+ unexpWarning()
+ edg_wll_freeBuf(XMLCtx);
+ }
+ break;
+ }
+
+ XMLCtx->char_buf = NULL;
+ XMLCtx->char_buf_len = 0;
+ memset(&(XMLCtx->element), 0, sizeof(XMLCtx->element));
+ XMLCtx->level--;
+
+}
+
+
+
+// XXX: endUserJobs should be unusable soon, delete it
+static void endUserJobs(void *data, const char *el UNUSED_VAR)
+{
+ edg_wll_XML_ctx *XMLCtx = data;
+ int i;
+
+
+ switch (XMLCtx->level) {
+ case 2 :
+ if (!strcmp(XMLCtx->element,"jobId")) {
+ XMLCtx->jobsOutGlobal[XMLCtx->position] =
+ edg_wll_from_string_to_jobid(XMLCtx);
+ XMLCtx->position++;
+ }
+ else {
+ /* tag was not found -> either missing in previous code or unknown */
+ unexpWarning()
+ edg_wll_freeBuf(XMLCtx);
+ }
+ break;
+ default:
+ /* only level 2 tags should contain text fields */
+ for (i=0; i < XMLCtx->char_buf_len; i++)
+ if (!isspace(XMLCtx->char_buf[i])) unexpWarning()
+ edg_wll_freeBuf(XMLCtx);
+ break;
+ }
+
+ memset(&(XMLCtx->element), 0, sizeof(XMLCtx->element));
+ // if ( !strcmp(XMLCtx->element,"jobId") ) XMLCtx->position++;
+ // uncomment this if you want to remove XMLCtx->position++; 5 lines above
+ // it should be useful in case of automatic generation
+ XMLCtx->level--;
+}
+
+
+
+static void endJobStat(void *data, const char *el)
+{
+ edg_wll_XML_ctx *XMLCtx = data;
+
+
+ switch (XMLCtx->level) {
+ case 2 :
+
+@@@{
+ my $i = 1;
+ my $bi = "\t ";
+ selectType $status '_common_';
+ for my $t (getFieldsOrdered $status) {
+ my $f = selectField $status $t;
+ my $ft = $f->{type};
+ next if defined($f->{special}) && $f->{special} eq 'XMLstructured';
+ if ($i == 1)
+ { gen "$bi if (!strcmp(XMLCtx->element,\"$t\"))\n"; }
+ else
+ { gen "$bi else if (!strcmp(XMLCtx->element,\"$t\"))\n"; }
+ $i++;
+ gen "$bi XMLCtx->jobStatSingleGlobal.$t =\n";
+ gen "$bi edg_wll_from_string_to_$ft(XMLCtx);\n";
+ }
+@@@}
+ else if (!strcmp(el,"children_hist")) {
+ long len = (XML_GetCurrentByteIndex(XMLCtx->p) + XML_GetCurrentByteCount(XMLCtx->p))
+ - XMLCtx->stat_begin;
+
+ edg_wll_ParseIntList(XMLCtx->ctx, XMLCtx->message_body + XMLCtx->stat_begin, len,
+ "children_hist",(int (*)()) edg_wll_StringToStat, &XMLCtx->jobStatSingleGlobal.children_hist);
+ XMLCtx->stat_begin = 0;
+ }
+ else if (!strcmp(el,"children")) {
+ long len = (XML_GetCurrentByteIndex(XMLCtx->p) + XML_GetCurrentByteCount(XMLCtx->p))
+ - XMLCtx->stat_begin;
+
+ edg_wll_ParseStrList(XMLCtx->ctx, XMLCtx->message_body + XMLCtx->stat_begin, len,
+ "children", "jobId", &XMLCtx->jobStatSingleGlobal.children);
+ XMLCtx->stat_begin = 0;
+ }
+ else if (!strcmp(el,"children_states")) {
+ long len = (XML_GetCurrentByteIndex(XMLCtx->p) + XML_GetCurrentByteCount(XMLCtx->p))
+ - XMLCtx->stat_begin;
+
+ edg_wll_ParseStsList(XMLCtx->ctx, XMLCtx->message_body + XMLCtx->stat_begin, len,
+ "children_states", "jobStat", &XMLCtx->jobStatSingleGlobal.children_states);
+ XMLCtx->stat_begin = 0;
+ }
+ else if (!strcmp(el,"user_tags")) {
+ long len = (XML_GetCurrentByteIndex(XMLCtx->p) + XML_GetCurrentByteCount(XMLCtx->p))
+ - XMLCtx->stat_begin;
+
+ edg_wll_ParseTagList(XMLCtx->ctx, XMLCtx->message_body + XMLCtx->stat_begin, len,
+ "user_tags", "tag", &XMLCtx->jobStatSingleGlobal.user_tags);
+ XMLCtx->stat_begin = 0;
+ }
+ else if (!strcmp(el,"stateEnterTimes")) {
+ long len = (XML_GetCurrentByteIndex(XMLCtx->p) + XML_GetCurrentByteCount(XMLCtx->p))
+ - XMLCtx->stat_begin;
+
+ edg_wll_ParseIntList(XMLCtx->ctx, XMLCtx->message_body + XMLCtx->stat_begin, len,
+ "stateEnterTimes",(int (*)()) edg_wll_StringToStat, &XMLCtx->jobStatSingleGlobal.stateEnterTimes);
+ XMLCtx->stat_begin = 0;
+ }
+ else {
+ /* tag was not found -> either missing in previous code or unknown */
+ unexpWarning()
+ edg_wll_freeBuf(XMLCtx);
+ }
+ break;
+ default:
+ if (XMLCtx->char_buf) {
+// unexpWarning()
+ edg_wll_freeBuf(XMLCtx);
+ }
+ break;
+ }
+
+ XMLCtx->char_buf = NULL;
+ XMLCtx->char_buf_len = 0;
+ memset(&(XMLCtx->element), 0, sizeof(XMLCtx->element));
+ XMLCtx->level--;
+}
+
+
+
+static void endStrList(void *data, const char *el UNUSED_VAR)
+{
+ edg_wll_XML_ctx *XMLCtx = data;
+
+
+ switch (XMLCtx->level) {
+ case 2 :
+ if (!strcmp(XMLCtx->element,XMLCtx->XML_tag2)) {
+ XMLCtx->strListGlobal[XMLCtx->position] =
+ edg_wll_from_string_to_string(XMLCtx);
+ XMLCtx->position++;
+ }
+ else {
+ /* tag was not found -> either missing in previous code or unknown */
+ unexpWarning()
+ edg_wll_freeBuf(XMLCtx);
+ }
+ break;
+ default:
+ if (XMLCtx->char_buf) {
+// unexpWarning()
+ edg_wll_freeBuf(XMLCtx);
+ }
+ break;
+ }
+
+ XMLCtx->char_buf = NULL;
+ XMLCtx->char_buf_len = 0;
+ memset(&(XMLCtx->element), 0, sizeof(XMLCtx->element));
+ XMLCtx->level--;
+}
+
+
+
+static void endIntList(void *data, const char *el UNUSED_VAR)
+{
+ edg_wll_XML_ctx *XMLCtx = data;
+ int index;
+
+
+ switch (XMLCtx->level) {
+ case 2 :
+ if ((index = XMLCtx->tagToIndex(XMLCtx->element)) >= 0 ) {
+ XMLCtx->intListGlobal[index+1] =
+ edg_wll_from_string_to_int(XMLCtx);
+ }
+ else {
+ /* tag was not found -> either missing in previous code or unknown */
+ unexpWarning()
+ edg_wll_freeBuf(XMLCtx);
+ }
+ break;
+ default:
+ if (XMLCtx->char_buf) {
+// unexpWarning()
+ edg_wll_freeBuf(XMLCtx);
+ }
+ break;
+ }
+
+ XMLCtx->char_buf = NULL;
+ XMLCtx->char_buf_len = 0;
+ memset(&(XMLCtx->element), 0, sizeof(XMLCtx->element));
+ XMLCtx->level--;
+}
+
+
+static void endTagList(void *data, const char *el UNUSED_VAR)
+{
+ edg_wll_XML_ctx *XMLCtx = data;
+
+
+ switch (XMLCtx->level) {
+ case 2 :
+ if (!strcmp(XMLCtx->element,XMLCtx->XML_tag2)) {
+ XMLCtx->tagListGlobal[XMLCtx->position].value =
+ edg_wll_from_string_to_string(XMLCtx);
+ XMLCtx->position++;
+ }
+ else {
+ /* tag was not found -> either missing in previous code or unknown */
+ unexpWarning()
+ edg_wll_freeBuf(XMLCtx);
+ }
+ break;
+ default:
+ if (XMLCtx->char_buf) {
+// unexpWarning()
+ edg_wll_freeBuf(XMLCtx);
+ }
+ break;
+ }
+
+ XMLCtx->char_buf = NULL;
+ XMLCtx->char_buf_len = 0;
+ memset(&(XMLCtx->element), 0, sizeof(XMLCtx->element));
+ XMLCtx->level--;
+}
+
+
+static void endStsList(void *data, const char *el)
+{
+ edg_wll_XML_ctx *XMLCtx = data;
+
+
+ switch (XMLCtx->level) {
+ case 2 :
+ if (!strcmp(el,XMLCtx->XML_tag2)) {
+ long len = (XML_GetCurrentByteIndex(XMLCtx->p) + XML_GetCurrentByteCount(XMLCtx->p))
+ - XMLCtx->stat_begin;
+
+ edg_wll_ParseJobStat(XMLCtx->ctx, XMLCtx->message_body + XMLCtx->stat_begin, len,
+ &XMLCtx->stsListGlobal[XMLCtx->position]);
+ XMLCtx->stat_begin = 0;
+ XMLCtx->position++;
+ }
+ else {
+ /* tag was not found -> either missing in previous code or unknown */
+ unexpWarning()
+ edg_wll_freeBuf(XMLCtx);
+ }
+ break;
+ default:
+ if (XMLCtx->char_buf) {
+// unexpWarning()
+ edg_wll_freeBuf(XMLCtx);
+ }
+ break;
+ }
+
+ XMLCtx->char_buf = NULL;
+ XMLCtx->char_buf_len = 0;
+ memset(&(XMLCtx->element), 0, sizeof(XMLCtx->element));
+ XMLCtx->level--;
+}
+
+
+
+
+static void endPurgeResult(void *data, const char *el UNUSED_VAR)
+{
+ edg_wll_XML_ctx *XMLCtx = data;
+ char *e;
+
+ if (XMLCtx->level == 2) {
+ if (!strcmp(XMLCtx->element,"server_file"))
+ XMLCtx->purgeResultGlobal.server_file = edg_wll_from_string_to_string(XMLCtx);
+ }
+ else if (XMLCtx->level == 3) {
+ if (!strcmp(XMLCtx->element,"jobId")) {
+ if ( (XMLCtx->purgeResultGlobal.jobs[XMLCtx->position++] =
+ edg_wll_from_string_to_string(XMLCtx)) == NULL )
+ {
+ if (XMLCtx->errtxt) {
+ asprintf(&e,"%s\n%s: invalid JobId at line %d",
+ XMLCtx->errtxt, XMLCtx->char_buf,
+ XML_GetCurrentLineNumber(XMLCtx->p));
+ free(XMLCtx->errtxt);
+ } else asprintf(&e,"%s: invalid JobId at line %d",
+ XMLCtx->char_buf,XML_GetCurrentLineNumber(XMLCtx->p));
+ XMLCtx->errtxt = e;
+ }
+ }
+ }
+
+ XMLCtx->char_buf = NULL;
+ XMLCtx->char_buf_len = 0;
+ XMLCtx->level--;
+}
+
+
+
+static void endDumpResult(void *data, const char *el UNUSED_VAR)
+{
+ edg_wll_XML_ctx *XMLCtx = data;
+
+ if (XMLCtx->level == 2) {
+ if (!strcmp(XMLCtx->element,"server_file"))
+ XMLCtx->dumpResultGlobal.server_file = edg_wll_from_string_to_string(XMLCtx);
+ else if (!strcmp(XMLCtx->element,"from")) {
+ if (isdigit(XMLCtx->char_buf[0]))
+ XMLCtx->dumpResultGlobal.from = edg_wll_from_string_to_time_t(XMLCtx);
+ else
+ XMLCtx->dumpResultGlobal.from = edg_wll_StringToDumpConst(XMLCtx->char_buf);
+ }
+ else if (!strcmp(XMLCtx->element,"to")) {
+ if (isdigit(XMLCtx->char_buf[0]))
+ XMLCtx->dumpResultGlobal.to = edg_wll_from_string_to_time_t(XMLCtx);
+ else
+ XMLCtx->dumpResultGlobal.to = edg_wll_StringToDumpConst(XMLCtx->char_buf);
+ }
+ }
+
+ XMLCtx->char_buf = NULL;
+ XMLCtx->char_buf_len = 0;
+ XMLCtx->level--;
+}
+
+
+
+static void endLoadResult(void *data, const char *el UNUSED_VAR)
+{
+ edg_wll_XML_ctx *XMLCtx = data;
+
+ if (XMLCtx->level == 2) {
+ if (!strcmp(XMLCtx->element,"server_file"))
+ XMLCtx->loadResultGlobal.server_file = edg_wll_from_string_to_string(XMLCtx);
+ else if (!strcmp(XMLCtx->element,"from"))
+ XMLCtx->loadResultGlobal.from = edg_wll_from_string_to_time_t(XMLCtx);
+ else if (!strcmp(XMLCtx->element,"to"))
+ XMLCtx->loadResultGlobal.to = edg_wll_from_string_to_time_t(XMLCtx);
+
+ }
+
+ XMLCtx->char_buf = NULL;
+ XMLCtx->char_buf_len = 0;
+ XMLCtx->level--;
+}
+
+
+
+static void endIndexedAttrs(void *data, const char *el)
+{
+ edg_wll_XML_ctx *XMLCtx = data;
+
+ if (XMLCtx->level == 2) {
+ if (!strcmp(el,"index"))
+ XMLCtx->position++;
+ XMLCtx->position2 = 0;
+ }
+ if (XMLCtx->level == 3) {
+ if (!strcmp(el,"QueryRec"))
+ XMLCtx->position2++;
+ }
+ if (XMLCtx->level == 4) {
+ if (!strcmp(XMLCtx->element,"attribute")) {
+ XMLCtx->attrsGlobal[XMLCtx->position][XMLCtx->position2].attr =
+ edg_wll_StringToquery_attr(edg_wll_from_string_to_string(XMLCtx));
+ }
+ else if (!strcmp(XMLCtx->element,"state")) {
+ XMLCtx->attrsGlobal[XMLCtx->position][XMLCtx->position2].attr_id.state =
+ edg_wll_StringToStat(edg_wll_from_string_to_string(XMLCtx));
+ }
+ else if (!strcmp(XMLCtx->element,"name")) {
+ XMLCtx->attrsGlobal[XMLCtx->position][XMLCtx->position2].attr_id.tag =
+ edg_wll_from_string_to_string(XMLCtx);
+ }
+ }
+
+ XMLCtx->char_buf = NULL;
+ XMLCtx->char_buf_len = 0;
+ XMLCtx->level--;
+}
+
+
+static void endNotifResult(void *data, const char *el UNUSED_VAR)
+{
+ edg_wll_XML_ctx *XMLCtx = data;
+
+
+ if (XMLCtx->level == 2) {
+ if (!strcmp(XMLCtx->element,"validity"))
+ XMLCtx->notifValidity = edg_wll_from_string_to_time_t(XMLCtx);
+ }
+
+ XMLCtx->char_buf = NULL;
+ XMLCtx->char_buf_len = 0;
+ XMLCtx->level--;
+}
+
+
+#undef unexpError
+#undef unexpWarning
+
+
+
+edg_wll_ErrorCode edg_wll_ParseQueryJobs(edg_wll_Context ctx, char *messageBody, edg_wlc_JobId **jobsOut, edg_wll_JobStat **statesOut)
+{
+ int i;
+ edg_wll_XML_ctx XMLCtx;
+ edg_wll_ErrorCode errorCode = 0;
+ XML_Char *encoding = "ISO-8859-1";
+
+
+ edg_wll_initXMLCtx(&XMLCtx);
+ edg_wll_ResetError(ctx);
+ XMLCtx.message_body = messageBody;
+ XMLCtx.ctx = ctx;
+
+ /* initialize parser */
+ XMLCtx.p = XML_ParserCreate(encoding);
+ XML_SetElementHandler(XMLCtx.p, startQueryJobs, endQueryJobs);
+ XML_SetCharacterDataHandler(XMLCtx.p, char_handler);
+ XML_SetUserData(XMLCtx.p, (void *) &XMLCtx);
+
+ /* parse messageBody */
+ if (! XML_Parse(XMLCtx.p, messageBody, strlen(messageBody), 1)) {
+ char *errorMessage;
+
+ asprintf(&errorMessage, "XML parse error at line %d:\n%s\n",
+ XML_GetCurrentLineNumber(XMLCtx.p),
+ XML_ErrorString(XML_GetErrorCode(XMLCtx.p)));
+
+ edg_wll_SetError(ctx, EDG_WLL_ERROR_XML_PARSE, errorMessage);
+ free(errorMessage);
+ } else if (XMLCtx.errtxt) edg_wll_SetError(ctx, EDG_WLL_ERROR_XML_PARSE, XMLCtx.errtxt);
+
+ if ((errorCode = edg_wll_Error(ctx,NULL,NULL))) {
+ for (i=0; i<XMLCtx.position; i++) edg_wlc_JobIdFree( (XMLCtx.jobsOutGlobal)[i] );
+ free(XMLCtx.jobsOutGlobal);
+ XMLCtx.jobsOutGlobal = NULL;
+ XMLCtx.position = 0;
+ if (jobsOut) *jobsOut = NULL;
+
+ for (i=0; i<XMLCtx.position2; i++) edg_wll_FreeStatus( &(XMLCtx.jobStatGlobal[i]) );
+ free(XMLCtx.jobStatGlobal);
+ XMLCtx.jobStatGlobal = NULL;
+ XMLCtx.position2 = 0;
+ if (statesOut) *statesOut = NULL;
+
+ if (XMLCtx.errDesc) {
+ free(XMLCtx.errDesc);
+ XMLCtx.errDesc = NULL;
+ XMLCtx.errCode = 0;
+ }
+ }
+
+ /* malloc-ate one more row for NULL list termination */
+ XMLCtx.jobsOutGlobal = realloc(XMLCtx.jobsOutGlobal,
+ (XMLCtx.position+1)*sizeof(*XMLCtx.jobsOutGlobal));
+
+ if (!XMLCtx.jobsOutGlobal) {
+ errorCode = (edg_wll_ErrorCode) ENOMEM;
+ if (jobsOut) *jobsOut = NULL;
+ }
+ else {
+ /* add NULL to end of list */
+ XMLCtx.jobsOutGlobal[XMLCtx.position] = NULL;
+
+ /* return results */
+ // XXX : may be should not be transfered; need to change protocol and
+ // XXX then return only non-NULL jobsOut or statesOut
+ if (jobsOut)
+ *jobsOut = XMLCtx.jobsOutGlobal;
+ else {
+ for (i=0; i<XMLCtx.position; i++) edg_wlc_JobIdFree( (XMLCtx.jobsOutGlobal)[i] );
+ free(XMLCtx.jobsOutGlobal);
+ }
+ XMLCtx.jobsOutGlobal = NULL;
+ }
+
+ XMLCtx.jobStatGlobal = realloc(XMLCtx.jobStatGlobal,
+ (XMLCtx.position2+1)*sizeof(*XMLCtx.jobStatGlobal));
+
+ if (!XMLCtx.jobStatGlobal) {
+ errorCode = (edg_wll_ErrorCode) ENOMEM;
+ if (statesOut) *statesOut = NULL;
+ }
+ else {
+ /* add NULL to end of list */
+ edg_wll_InitStatus(&XMLCtx.jobStatGlobal[XMLCtx.position2]);
+
+ /* return results */
+ if (statesOut)
+ *statesOut = XMLCtx.jobStatGlobal;
+ else {
+ for (i=0; i<XMLCtx.position2; i++) edg_wll_FreeStatus( &(XMLCtx.jobStatGlobal[i]) );
+ free(XMLCtx.jobStatGlobal);
+ }
+
+ XMLCtx.jobStatGlobal = NULL;
+ }
+
+ if (XMLCtx.errDesc || XMLCtx.errCode) {
+ ctx->errDesc = XMLCtx.errDesc;
+ ctx->errCode = XMLCtx.errCode;
+ }
+
+
+ /* print all warning if corresponding env variable is set */
+ if (XMLCtx.warntxt && getenv("EDG_WLL_XML_WARNINGS")) {
+
+ fprintf(stderr,"----------------------------------------------------\n");
+ fprintf(stderr,"%s\n\n",XMLCtx.warntxt);
+ fprintf(stderr,"%s\n",messageBody);
+ fprintf(stderr,"----------------------------------------------------\n");
+ }
+
+ /* free parser */
+ XML_ParserFree(XMLCtx.p);
+
+ edg_wll_freeXMLCtx(&XMLCtx);
+ return errorCode;
+}
+
+
+
+edg_wll_ErrorCode edg_wll_ParseQueryEvents(edg_wll_Context ctx, char *messageBody, edg_wll_Event **eventsOut)
+{
+ int i;
+ edg_wll_XML_ctx XMLCtx;
+ edg_wll_ErrorCode errorCode = 0;
+ XML_Char *encoding = "ISO-8859-1";
+
+
+ edg_wll_initXMLCtx(&XMLCtx);
+ XMLCtx.position = -1;
+ edg_wll_ResetError(ctx);
+
+ /* initialize parser */
+ XMLCtx.p = XML_ParserCreate(encoding);
+ XML_SetElementHandler(XMLCtx.p, startQueryEvents, endQueryEvents);
+ XML_SetCharacterDataHandler(XMLCtx.p, char_handler);
+ XML_SetUserData(XMLCtx.p, (void *) &XMLCtx);
+
+ /* parse messageBody */
+ if (! XML_Parse(XMLCtx.p, messageBody, strlen(messageBody), 1)) {
+ char *errorMessage;
+
+
+ asprintf(&errorMessage, "XML parse error at line %d:\n%s\n",
+ XML_GetCurrentLineNumber(XMLCtx.p),
+ XML_ErrorString(XML_GetErrorCode(XMLCtx.p)));
+
+ edg_wll_SetError(ctx, EDG_WLL_ERROR_XML_PARSE, errorMessage);
+ free(errorMessage);
+ } else if (XMLCtx.errtxt) edg_wll_SetError(ctx, EDG_WLL_ERROR_XML_PARSE, XMLCtx.errtxt);
+
+ if ((errorCode = edg_wll_Error(ctx,NULL,NULL))) {
+ *eventsOut = NULL;
+ for (i=0; i<= XMLCtx.position; i++) edg_wll_FreeEvent( &((XMLCtx.eventsOutGlobal)[i]) );
+ free(XMLCtx.eventsOutGlobal);
+ XMLCtx.eventsOutGlobal = NULL;
+
+ if (XMLCtx.errDesc) {
+ free(XMLCtx.errDesc);
+ XMLCtx.errDesc = NULL;
+ XMLCtx.errCode = 0;
+ }
+ }
+ else {
+ /* malloc-ate one more row for NULL list termination */
+ XMLCtx.eventsOutGlobal = realloc(XMLCtx.eventsOutGlobal,
+ (++XMLCtx.position+1)*sizeof(*XMLCtx.eventsOutGlobal));
+ if (!XMLCtx.eventsOutGlobal) {
+ errorCode = (edg_wll_ErrorCode) ENOMEM;
+ *eventsOut = NULL;
+ }
+ else {
+ /* last event in list is EDG_WLL_EVENT_UNDEF for end-of-list detection */
+ memset(&XMLCtx.eventsOutGlobal[XMLCtx.position],0,sizeof(*XMLCtx.eventsOutGlobal));
+ XMLCtx.eventsOutGlobal[XMLCtx.position].any.type = EDG_WLL_EVENT_UNDEF;
+
+ /* return results */
+ *eventsOut = XMLCtx.eventsOutGlobal;
+ XMLCtx.eventsOutGlobal = NULL;
+ }
+ }
+
+ if (XMLCtx.errDesc || XMLCtx.errCode) {
+ ctx->errDesc = XMLCtx.errDesc;
+ ctx->errCode = XMLCtx.errCode;
+ }
+
+ /* print all warning if corresponding env variable is set */
+ if (XMLCtx.warntxt && getenv("EDG_WLL_XML_WARNINGS")) {
+ fprintf(stderr,"------------------------edg_wll_ParseQueryEvents----------------------------\n");
+ fprintf(stderr,"%s\n\n",XMLCtx.warntxt);
+ fprintf(stderr,"%s\n",messageBody);
+ fprintf(stderr,"----------------------------------------------------\n");
+ }
+
+ /* free parser */
+ XML_ParserFree(XMLCtx.p);
+
+ edg_wll_freeXMLCtx(&XMLCtx);
+ return errorCode;
+}
+
+
+
+
+edg_wll_ErrorCode edg_wll_ParseUserJobs(edg_wll_Context ctx, char *messageBody, edg_wlc_JobId **jobsOut)
+{
+ int i;
+ edg_wll_XML_ctx XMLCtx;
+ edg_wll_ErrorCode errorCode = 0;
+ XML_Char *encoding = "ISO-8859-1";
+
+
+ edg_wll_initXMLCtx(&XMLCtx);
+ edg_wll_ResetError(ctx);
+
+ /* initialize parser */
+ XMLCtx.p = XML_ParserCreate(encoding);
+ XML_SetElementHandler(XMLCtx.p, startUserJobs, endUserJobs);
+ XML_SetCharacterDataHandler(XMLCtx.p, char_handler);
+ XML_SetUserData(XMLCtx.p, (void *) &XMLCtx);
+
+ /* parse messageBody */
+ if (! XML_Parse(XMLCtx.p, messageBody, strlen(messageBody), 1)) {
+ char *errorMessage;
+
+
+ asprintf(&errorMessage, "XML parse error at line %d:\n%s\n",
+ XML_GetCurrentLineNumber(XMLCtx.p),
+ XML_ErrorString(XML_GetErrorCode(XMLCtx.p)));
+ *jobsOut = NULL;
+
+ edg_wll_SetError(ctx, EDG_WLL_ERROR_XML_PARSE, errorMessage);
+ free(errorMessage);
+ } else if (XMLCtx.errtxt) edg_wll_SetError(ctx, EDG_WLL_ERROR_XML_PARSE, XMLCtx.errtxt);
+
+ if ((errorCode = edg_wll_Error(ctx,NULL,NULL))) {
+ *jobsOut = NULL;
+ for (i=0; i<XMLCtx.position; i++) edg_wlc_JobIdFree( (XMLCtx.jobsOutGlobal)[i] );
+ free(XMLCtx.jobsOutGlobal);
+ XMLCtx.jobsOutGlobal = NULL;
+ } else {
+ /* malloc-ate one more row for NULL list termination */
+ XMLCtx.jobsOutGlobal = realloc(XMLCtx.jobsOutGlobal,
+ (XMLCtx.position+1)*sizeof(*XMLCtx.jobsOutGlobal));
+ if (!XMLCtx.jobsOutGlobal) {
+ errorCode = (edg_wll_ErrorCode) ENOMEM;
+ *jobsOut = NULL;
+ }
+ else {
+ /* add NULL to end of list */
+ XMLCtx.jobsOutGlobal[XMLCtx.position] = NULL;
+
+ /* return results */
+ *jobsOut = XMLCtx.jobsOutGlobal;
+ XMLCtx.jobsOutGlobal = NULL;
+ }
+ }
+
+ /* print all warning if corresponding env variable is set */
+ if (XMLCtx.warntxt && getenv("EDG_WLL_XML_WARNINGS")) {
+ fprintf(stderr,"----------------------------------------------------\n");
+ fprintf(stderr,"%s\n\n",XMLCtx.warntxt);
+ fprintf(stderr,"%s\n",messageBody);
+ fprintf(stderr,"----------------------------------------------------\n");
+ }
+
+ /* free parser */
+ XML_ParserFree(XMLCtx.p);
+
+ edg_wll_freeXMLCtx(&XMLCtx);
+ return errorCode;
+}
+
+
+
+edg_wll_ErrorCode edg_wll_ParseJobStat(edg_wll_Context ctx, char *messageBody, long len, edg_wll_JobStat *stat)
+{
+ edg_wll_XML_ctx XMLCtx;
+ edg_wll_ErrorCode errorCode;
+ XML_Char *encoding = "ISO-8859-1";
+
+
+ edg_wll_initXMLCtx(&XMLCtx);
+ edg_wll_ResetError(ctx);
+ XMLCtx.message_body = messageBody;
+ XMLCtx.ctx = ctx;
+
+ /* initialize parser */
+ XMLCtx.p = XML_ParserCreate(encoding);
+ XML_SetElementHandler(XMLCtx.p, startJobStatus, endJobStat);
+ XML_SetCharacterDataHandler(XMLCtx.p, char_handler);
+ XML_SetUserData(XMLCtx.p, (void *) &XMLCtx);
+
+ /* parse messageBody */
+ if (! XML_Parse(XMLCtx.p, messageBody, len, 1)) {
+ char *errorMessage;
+
+
+ asprintf(&errorMessage, "Parse error at line %d:\n%s\n",
+ XML_GetCurrentLineNumber(XMLCtx.p),
+ XML_ErrorString(XML_GetErrorCode(XMLCtx.p)));
+
+ edg_wll_SetError(ctx, EDG_WLL_ERROR_XML_PARSE, errorMessage);
+ free(errorMessage);
+ } else if (XMLCtx.errtxt) edg_wll_SetError(ctx, EDG_WLL_ERROR_XML_PARSE, XMLCtx.errtxt);
+
+ if ((errorCode = edg_wll_Error(ctx,NULL,NULL))) {
+ edg_wll_FreeStatus( &XMLCtx.jobStatSingleGlobal );
+ memset(stat,0,sizeof(*stat));
+ XMLCtx.position = 0;
+ }
+ else {
+ /* return results */
+ memcpy(stat, &XMLCtx.jobStatSingleGlobal, sizeof(XMLCtx.jobStatSingleGlobal));
+ }
+
+ /* print all warning if corresponding env variable is set */
+ if (XMLCtx.warntxt && getenv("EDG_WLL_XML_WARNINGS")) {
+ fprintf(stderr,"----------------------------------------------------\n");
+ fprintf(stderr,"%s\n\n",XMLCtx.warntxt);
+ fprintf(stderr,"%s\n",messageBody);
+ fprintf(stderr,"----------------------------------------------------\n");
+ }
+
+ /* free parser */
+ XML_ParserFree(XMLCtx.p);
+
+ edg_wll_freeXMLCtx(&XMLCtx);
+ return errorCode;
+}
+
+
+edg_wll_ErrorCode edg_wll_ParseStrList(edg_wll_Context ctx, char *messageBody, long len, char *tag, char *tag2, char ***strListOut)
+{
+ edg_wll_XML_ctx XMLCtx;
+ edg_wll_ErrorCode errorCode;
+ XML_Char *encoding = "ISO-8859-1";
+
+
+ edg_wll_initXMLCtx(&XMLCtx);
+ edg_wll_ResetError(ctx);
+ XMLCtx.message_body = messageBody;
+ XMLCtx.ctx = ctx;
+ asprintf(&XMLCtx.XML_tag,"%s",tag);
+ asprintf(&XMLCtx.XML_tag2,"%s",tag2);
+
+ /* initialize parser */
+ XMLCtx.p = XML_ParserCreate(encoding);
+ XML_SetElementHandler(XMLCtx.p, startStrList, endStrList);
+ XML_SetCharacterDataHandler(XMLCtx.p, char_handler);
+ XML_SetUserData(XMLCtx.p, (void *) &XMLCtx);
+
+ /* parse messageBody */
+ if (! XML_Parse(XMLCtx.p, messageBody, len, 1)) {
+ char *errorMessage;
+
+
+ asprintf(&errorMessage, "Parse error at line %d:\n%s\n",
+ XML_GetCurrentLineNumber(XMLCtx.p),
+ XML_ErrorString(XML_GetErrorCode(XMLCtx.p)));
+
+ edg_wll_SetError(ctx, EDG_WLL_ERROR_XML_PARSE, errorMessage);
+ free(errorMessage);
+ } else if (XMLCtx.errtxt) edg_wll_SetError(ctx, EDG_WLL_ERROR_XML_PARSE, XMLCtx.errtxt);
+
+ if ((errorCode = edg_wll_Error(ctx,NULL,NULL))) {
+ if (XMLCtx.strListGlobal) {
+ int i;
+
+ for (i=0; XMLCtx.strListGlobal[i]; i++)
+ free(XMLCtx.strListGlobal[i]);
+ free(XMLCtx.strListGlobal);
+ XMLCtx.strListGlobal = NULL;
+ }
+ *strListOut = NULL;
+ XMLCtx.position = 0;
+ }
+ else {
+ XMLCtx.strListGlobal = realloc(XMLCtx.strListGlobal,
+ (XMLCtx.position+1)*sizeof(*XMLCtx.strListGlobal));
+
+ if (!XMLCtx.strListGlobal) {
+ errorCode = (edg_wll_ErrorCode) ENOMEM;
+ if (strListOut) *strListOut = NULL;
+ }
+ else {
+ /* add NULL to end of list */
+ XMLCtx.strListGlobal[XMLCtx.position] = NULL;
+
+ /* return results */
+ *strListOut = XMLCtx.strListGlobal;
+ }
+ }
+
+ /* print all warning if corresponding env variable is set */
+ if (XMLCtx.warntxt && getenv("EDG_WLL_XML_WARNINGS")) {
+ fprintf(stderr,"----------------------------------------------------\n");
+ fprintf(stderr,"%s\n\n",XMLCtx.warntxt);
+ fprintf(stderr,"%s\n",messageBody);
+ fprintf(stderr,"----------------------------------------------------\n");
+ }
+
+ /* free parser */
+ XML_ParserFree(XMLCtx.p);
+
+ edg_wll_freeXMLCtx(&XMLCtx);
+ return errorCode;
+}
+
+
+edg_wll_ErrorCode edg_wll_ParseIntList(edg_wll_Context ctx, char *messageBody, long len, char *tag, int (*tagToIndex)(), int **intListOut)
+{
+ edg_wll_XML_ctx XMLCtx;
+ edg_wll_ErrorCode errorCode;
+ XML_Char *encoding = "ISO-8859-1";
+
+
+ edg_wll_initXMLCtx(&XMLCtx);
+ edg_wll_ResetError(ctx);
+ XMLCtx.message_body = messageBody;
+ XMLCtx.ctx = ctx;
+ asprintf(&XMLCtx.XML_tag,"%s",tag);
+ XMLCtx.tagToIndex = tagToIndex;
+
+ /* initialize parser */
+ XMLCtx.p = XML_ParserCreate(encoding);
+ XML_SetElementHandler(XMLCtx.p, startIntList, endIntList);
+ XML_SetCharacterDataHandler(XMLCtx.p, char_handler);
+ XML_SetUserData(XMLCtx.p, (void *) &XMLCtx);
+
+ /* parse messageBody */
+ if (! XML_Parse(XMLCtx.p, messageBody, len, 1)) {
+ char *errorMessage;
+
+
+ asprintf(&errorMessage, "Parse error at line %d:\n%s\n",
+ XML_GetCurrentLineNumber(XMLCtx.p),
+ XML_ErrorString(XML_GetErrorCode(XMLCtx.p)));
+
+ edg_wll_SetError(ctx, EDG_WLL_ERROR_XML_PARSE, errorMessage);
+ free(errorMessage);
+ } else if (XMLCtx.errtxt) edg_wll_SetError(ctx, EDG_WLL_ERROR_XML_PARSE, XMLCtx.errtxt);
+
+ if ((errorCode = edg_wll_Error(ctx,NULL,NULL))) {
+ if (XMLCtx.intListGlobal) free(XMLCtx.intListGlobal);
+ *intListOut = NULL;
+ XMLCtx.max_index = 0;
+ }
+ else {
+ /* add array length to zeros' position */
+ if (XMLCtx.intListGlobal)
+ XMLCtx.intListGlobal[0] = XMLCtx.max_index + 1;
+
+ /* return results */
+ *intListOut = XMLCtx.intListGlobal;
+ }
+
+ /* print all warning if corresponding env variable is set */
+ if (XMLCtx.warntxt && getenv("EDG_WLL_XML_WARNINGS")) {
+ fprintf(stderr,"----------------------------------------------------\n");
+ fprintf(stderr,"%s\n\n",XMLCtx.warntxt);
+ fprintf(stderr,"%s\n",messageBody);
+ fprintf(stderr,"----------------------------------------------------\n");
+ }
+
+ /* free parser */
+ XML_ParserFree(XMLCtx.p);
+
+ edg_wll_freeXMLCtx(&XMLCtx);
+ return errorCode;
+}
+
+
+edg_wll_ErrorCode edg_wll_ParseTagList(edg_wll_Context ctx, char *messageBody, long len, char *tag, char *tag2, edg_wll_TagValue **tagListOut)
+{
+ edg_wll_XML_ctx XMLCtx;
+ edg_wll_ErrorCode errorCode;
+ XML_Char *encoding = "ISO-8859-1";
+
+
+ edg_wll_initXMLCtx(&XMLCtx);
+ edg_wll_ResetError(ctx);
+ XMLCtx.message_body = messageBody;
+ XMLCtx.ctx = ctx;
+ asprintf(&XMLCtx.XML_tag,"%s",tag);
+ asprintf(&XMLCtx.XML_tag2,"%s",tag2);
+
+ /* initialize parser */
+ XMLCtx.p = XML_ParserCreate(encoding);
+ XML_SetElementHandler(XMLCtx.p, startTagList, endTagList);
+ XML_SetCharacterDataHandler(XMLCtx.p, char_handler);
+ XML_SetUserData(XMLCtx.p, (void *) &XMLCtx);
+
+ /* parse messageBody */
+ if (! XML_Parse(XMLCtx.p, messageBody, len, 1)) {
+ char *errorMessage;
+
+
+ asprintf(&errorMessage, "Parse error at line %d:\n%s\n",
+ XML_GetCurrentLineNumber(XMLCtx.p),
+ XML_ErrorString(XML_GetErrorCode(XMLCtx.p)));
+
+ edg_wll_SetError(ctx, EDG_WLL_ERROR_XML_PARSE, errorMessage);
+ free(errorMessage);
+ } else if (XMLCtx.errtxt) edg_wll_SetError(ctx, EDG_WLL_ERROR_XML_PARSE, XMLCtx.errtxt);
+
+ if ((errorCode = edg_wll_Error(ctx,NULL,NULL))) {
+ if (XMLCtx.tagListGlobal) {
+ int i;
+
+ for (i=0; XMLCtx.tagListGlobal[i].tag; i++) {
+ free(XMLCtx.tagListGlobal[i].tag);
+ free(XMLCtx.tagListGlobal[i].value);
+ }
+ free(XMLCtx.tagListGlobal);
+ XMLCtx.tagListGlobal = NULL;
+ }
+ *tagListOut = NULL;
+ XMLCtx.position = 0;
+ }
+ else {
+ XMLCtx.tagListGlobal = realloc(XMLCtx.tagListGlobal,
+ (XMLCtx.position+1)*sizeof(*XMLCtx.tagListGlobal));
+
+ if (!XMLCtx.tagListGlobal) {
+ errorCode = (edg_wll_ErrorCode) ENOMEM;
+ if (tagListOut) *tagListOut = NULL;
+ }
+ else {
+ /* add NULL to end of list */
+ XMLCtx.tagListGlobal[XMLCtx.position].tag = NULL;
+
+ /* return results */
+ *tagListOut = XMLCtx.tagListGlobal;
+ }
+ }
+
+ /* print all warning if corresponding env variable is set */
+ if (XMLCtx.warntxt && getenv("EDG_WLL_XML_WARNINGS")) {
+ fprintf(stderr,"----------------------------------------------------\n");
+ fprintf(stderr,"%s\n\n",XMLCtx.warntxt);
+ fprintf(stderr,"%s\n",messageBody);
+ fprintf(stderr,"----------------------------------------------------\n");
+ }
+
+ /* free parser */
+ XML_ParserFree(XMLCtx.p);
+
+ edg_wll_freeXMLCtx(&XMLCtx);
+ return errorCode;
+}
+
+
+
+edg_wll_ErrorCode edg_wll_ParseStsList(edg_wll_Context ctx, char *messageBody, long len, char *tag, char *tag2, edg_wll_JobStat **stsListOut)
+{
+ edg_wll_XML_ctx XMLCtx;
+ edg_wll_ErrorCode errorCode;
+ XML_Char *encoding = "ISO-8859-1";
+
+
+ edg_wll_initXMLCtx(&XMLCtx);
+ edg_wll_ResetError(ctx);
+ XMLCtx.message_body = messageBody;
+ XMLCtx.ctx = ctx;
+ asprintf(&XMLCtx.XML_tag,"%s",tag);
+ asprintf(&XMLCtx.XML_tag2,"%s",tag2);
+
+ /* initialize parser */
+ XMLCtx.p = XML_ParserCreate(encoding);
+ XML_SetElementHandler(XMLCtx.p, startStsList, endStsList);
+ XML_SetCharacterDataHandler(XMLCtx.p, char_handler);
+ XML_SetUserData(XMLCtx.p, (void *) &XMLCtx);
+
+ /* parse messageBody */
+ if (! XML_Parse(XMLCtx.p, messageBody, len, 1)) {
+ char *errorMessage;
+
+
+ asprintf(&errorMessage, "Parse error at line %d:\n%s\n",
+ XML_GetCurrentLineNumber(XMLCtx.p),
+ XML_ErrorString(XML_GetErrorCode(XMLCtx.p)));
+
+ edg_wll_SetError(ctx, EDG_WLL_ERROR_XML_PARSE, errorMessage);
+ free(errorMessage);
+ } else if (XMLCtx.errtxt) edg_wll_SetError(ctx, EDG_WLL_ERROR_XML_PARSE, XMLCtx.errtxt);
+
+ if ((errorCode = edg_wll_Error(ctx,NULL,NULL))) {
+ if (XMLCtx.stsListGlobal) {
+ int i;
+
+ for (i=0; XMLCtx.position; i++)
+ edg_wll_FreeStatus(&XMLCtx.stsListGlobal[i]);
+ free(XMLCtx.stsListGlobal);
+ XMLCtx.stsListGlobal = NULL;
+ }
+ *stsListOut = NULL;
+ XMLCtx.position = 0;
+ }
+ else {
+ XMLCtx.stsListGlobal = realloc(XMLCtx.stsListGlobal,
+ (XMLCtx.position+1)*sizeof(*XMLCtx.stsListGlobal));
+
+ if (!XMLCtx.stsListGlobal) {
+ errorCode = (edg_wll_ErrorCode) ENOMEM;
+ if (stsListOut) *stsListOut = NULL;
+ }
+ else {
+ /* add NULL to end of list */
+ edg_wll_InitStatus(&XMLCtx.stsListGlobal[XMLCtx.position]);
+
+ /* return results */
+ *stsListOut = XMLCtx.stsListGlobal;
+ }
+ }
+
+ /* print all warning if corresponding env variable is set */
+ if (XMLCtx.warntxt && getenv("EDG_WLL_XML_WARNINGS")) {
+ fprintf(stderr,"----------------------------------------------------\n");
+ fprintf(stderr,"%s\n\n",XMLCtx.warntxt);
+ fprintf(stderr,"%s\n",messageBody);
+ fprintf(stderr,"----------------------------------------------------\n");
+ }
+
+ /* free parser */
+ XML_ParserFree(XMLCtx.p);
+
+ edg_wll_freeXMLCtx(&XMLCtx);
+ return errorCode;
+}
+
+
+
+/* parse purge result from client */
+edg_wll_ErrorCode edg_wll_ParsePurgeResult(edg_wll_Context ctx, char *messageBody, edg_wll_PurgeResult *result)
+{
+ edg_wll_XML_ctx XMLCtx;
+ edg_wll_ErrorCode errorCode;
+ XML_Char *encoding = "ISO-8859-1";
+
+ errno = 0;
+ edg_wll_ResetError(ctx);
+ edg_wll_initXMLCtx(&XMLCtx);
+ XMLCtx.ctx = ctx;
+
+
+ /* initialize parser */
+ XMLCtx.p = XML_ParserCreate(encoding);
+ XML_SetElementHandler(XMLCtx.p, startPurgeResult, endPurgeResult);
+ XML_SetCharacterDataHandler(XMLCtx.p, char_handler);
+ XML_SetUserData(XMLCtx.p, (void *) &XMLCtx);
+
+
+ if (! XML_Parse(XMLCtx.p, messageBody, strlen(messageBody), 1)) {
+ char *errorMessage;
+
+ asprintf(&errorMessage, "Parse error at line %d:\n%s\n",
+ XML_GetCurrentLineNumber(XMLCtx.p),
+ XML_ErrorString(XML_GetErrorCode(XMLCtx.p)));
+
+ edg_wll_SetError(ctx, EDG_WLL_ERROR_XML_PARSE, errorMessage);
+ free(errorMessage);
+ } else if (XMLCtx.errtxt) edg_wll_SetError(ctx, EDG_WLL_ERROR_XML_PARSE, XMLCtx.errtxt);
+
+
+ if ((errorCode = edg_wll_Error(ctx,NULL,NULL))) {
+ int i;
+
+ if (XMLCtx.purgeResultGlobal.jobs) {
+ for (i=0; XMLCtx.purgeResultGlobal.jobs[i]; i++)
+ free(XMLCtx.purgeResultGlobal.jobs[i]);
+ free(XMLCtx.purgeResultGlobal.jobs);
+ }
+ memset(result,0,sizeof(*result));
+ free(XMLCtx.purgeResultGlobal.server_file);
+
+ } else {
+ memcpy(result, &XMLCtx.purgeResultGlobal, sizeof(XMLCtx.purgeResultGlobal));
+ }
+
+ if (XMLCtx.errDesc || XMLCtx.errCode) {
+ ctx->errDesc = XMLCtx.errDesc;
+ ctx->errCode = XMLCtx.errCode;
+ }
+
+ /* print all warning if corresponding env variable is set */
+ if (XMLCtx.warntxt && getenv("EDG_WLL_XML_WARNINGS")) {
+ fprintf(stderr,"----------------------------------------------------\n");
+ fprintf(stderr,"%s\n\n",XMLCtx.warntxt);
+ fprintf(stderr,"%s\n",messageBody);
+ fprintf(stderr,"----------------------------------------------------\n");
+ }
+
+ /* free parser */
+ XML_ParserFree(XMLCtx.p);
+
+ edg_wll_freeXMLCtx(&XMLCtx);
+ return errorCode;
+}
+
+
+
+/* parse dump result from client */
+edg_wll_ErrorCode edg_wll_ParseDumpResult(edg_wll_Context ctx, char *messageBody, edg_wll_DumpResult *result)
+{
+ edg_wll_XML_ctx XMLCtx;
+ edg_wll_ErrorCode errorCode;
+ XML_Char *encoding = "ISO-8859-1";
+
+ errno = 0;
+ edg_wll_ResetError(ctx);
+ edg_wll_initXMLCtx(&XMLCtx);
+ XMLCtx.ctx = ctx;
+
+
+ /* initialize parser */
+ XMLCtx.p = XML_ParserCreate(encoding);
+ XML_SetElementHandler(XMLCtx.p, startDumpResult, endDumpResult);
+ XML_SetCharacterDataHandler(XMLCtx.p, char_handler);
+ XML_SetUserData(XMLCtx.p, (void *) &XMLCtx);
+
+
+ if (! XML_Parse(XMLCtx.p, messageBody, strlen(messageBody), 1)) {
+ char *errorMessage;
+
+ asprintf(&errorMessage, "Parse error at line %d:\n%s\n",
+ XML_GetCurrentLineNumber(XMLCtx.p),
+ XML_ErrorString(XML_GetErrorCode(XMLCtx.p)));
+
+ edg_wll_SetError(ctx, EDG_WLL_ERROR_XML_PARSE, errorMessage);
+ free(errorMessage);
+ } else if (XMLCtx.errtxt) edg_wll_SetError(ctx, EDG_WLL_ERROR_XML_PARSE, XMLCtx.errtxt);
+
+
+ if ((errorCode = edg_wll_Error(ctx,NULL,NULL))) {
+ free(XMLCtx.dumpResultGlobal.server_file);
+ memset(result,0,sizeof(*result));
+ } else {
+ memcpy(result, &XMLCtx.dumpResultGlobal, sizeof(XMLCtx.dumpResultGlobal));
+ }
+
+ if (XMLCtx.errDesc || XMLCtx.errCode) {
+ ctx->errDesc = XMLCtx.errDesc;
+ ctx->errCode = XMLCtx.errCode;
+ }
+
+ /* print all warning if corresponding env variable is set */
+ if (XMLCtx.warntxt && getenv("EDG_WLL_XML_WARNINGS")) {
+ fprintf(stderr,"----------------------------------------------------\n");
+ fprintf(stderr,"%s\n\n",XMLCtx.warntxt);
+ fprintf(stderr,"%s\n",messageBody);
+ fprintf(stderr,"----------------------------------------------------\n");
+ }
+
+ /* free parser */
+ XML_ParserFree(XMLCtx.p);
+
+ edg_wll_freeXMLCtx(&XMLCtx);
+ return errorCode;
+}
+
+
+
+/* parse load result from client */
+edg_wll_ErrorCode edg_wll_ParseLoadResult(edg_wll_Context ctx, char *messageBody, edg_wll_LoadResult *result)
+{
+ edg_wll_XML_ctx XMLCtx;
+ edg_wll_ErrorCode errorCode;
+ XML_Char *encoding = "ISO-8859-1";
+
+ errno = 0;
+ edg_wll_ResetError(ctx);
+ edg_wll_initXMLCtx(&XMLCtx);
+ XMLCtx.ctx = ctx;
+
+
+ /* initialize parser */
+ XMLCtx.p = XML_ParserCreate(encoding);
+ XML_SetElementHandler(XMLCtx.p, startLoadResult, endLoadResult);
+ XML_SetCharacterDataHandler(XMLCtx.p, char_handler);
+ XML_SetUserData(XMLCtx.p, (void *) &XMLCtx);
+
+
+ if (! XML_Parse(XMLCtx.p, messageBody, strlen(messageBody), 1)) {
+ char *errorMessage;
+
+ asprintf(&errorMessage, "Parse error at line %d:\n%s\n",
+ XML_GetCurrentLineNumber(XMLCtx.p),
+ XML_ErrorString(XML_GetErrorCode(XMLCtx.p)));
+
+ edg_wll_SetError(ctx, EDG_WLL_ERROR_XML_PARSE, errorMessage);
+ free(errorMessage);
+ } else if (XMLCtx.errtxt) edg_wll_SetError(ctx, EDG_WLL_ERROR_XML_PARSE, XMLCtx.errtxt);
+
+
+ if ((errorCode = edg_wll_Error(ctx,NULL,NULL))) {
+ free(XMLCtx.loadResultGlobal.server_file);
+ memset(result,0,sizeof(*result));
+ } else {
+ memcpy(result, &XMLCtx.loadResultGlobal, sizeof(XMLCtx.loadResultGlobal));
+ }
+
+ if (XMLCtx.errDesc || XMLCtx.errCode) {
+ ctx->errDesc = XMLCtx.errDesc;
+ ctx->errCode = XMLCtx.errCode;
+ }
+
+ /* print all warning if corresponding env variable is set */
+ if (XMLCtx.warntxt && getenv("EDG_WLL_XML_WARNINGS")) {
+ fprintf(stderr,"----------------------------------------------------\n");
+ fprintf(stderr,"%s\n\n",XMLCtx.warntxt);
+ fprintf(stderr,"%s\n",messageBody);
+ fprintf(stderr,"----------------------------------------------------\n");
+ }
+
+ /* free parser */
+ XML_ParserFree(XMLCtx.p);
+
+ edg_wll_freeXMLCtx(&XMLCtx);
+ return errorCode;
+}
+
+
+
+edg_wll_ErrorCode edg_wll_ParseIndexedAttrs(edg_wll_Context ctx, char *messageBody, edg_wll_QueryRec ***attrs)
+{
+ edg_wll_XML_ctx XMLCtx;
+ edg_wll_ErrorCode errorCode;
+ XML_Char *encoding = "ISO-8859-1";
+
+
+ edg_wll_initXMLCtx(&XMLCtx);
+ edg_wll_ResetError(ctx);
+ XMLCtx.message_body = messageBody;
+ XMLCtx.ctx = ctx;
+
+ /* initialize parser */
+ XMLCtx.p = XML_ParserCreate(encoding);
+ XML_SetElementHandler(XMLCtx.p, startIndexedAttrs, endIndexedAttrs);
+ XML_SetCharacterDataHandler(XMLCtx.p, char_handler);
+ XML_SetUserData(XMLCtx.p, (void *) &XMLCtx);
+
+ /* parse messageBody */
+ if (! XML_Parse(XMLCtx.p, messageBody, strlen(messageBody), 1)) {
+ char *errorMessage;
+
+
+ asprintf(&errorMessage, "Parse error at line %d:\n%s\n",
+ XML_GetCurrentLineNumber(XMLCtx.p),
+ XML_ErrorString(XML_GetErrorCode(XMLCtx.p)));
+
+ edg_wll_SetError(ctx, EDG_WLL_ERROR_XML_PARSE, errorMessage);
+ free(errorMessage);
+ } else if (XMLCtx.errtxt) edg_wll_SetError(ctx, EDG_WLL_ERROR_XML_PARSE, XMLCtx.errtxt);
+
+ if ((errorCode = edg_wll_Error(ctx,NULL,NULL))) {
+ if (XMLCtx.attrsGlobal) {
+ int i,j;
+
+ for (i=0; XMLCtx.attrsGlobal[i]; i++) {
+ for (j=0; XMLCtx.attrsGlobal[i][j].attr != EDG_WLL_QUERY_ATTR_UNDEF; j++) {
+ if (XMLCtx.attrsGlobal[i][j].attr == EDG_WLL_QUERY_ATTR_USERTAG)
+ free(XMLCtx.attrsGlobal[i][j].attr_id.tag);
+ }
+ free(XMLCtx.attrsGlobal[i]);
+ }
+ free(XMLCtx.attrsGlobal);
+ XMLCtx.attrsGlobal = NULL;
+ }
+ XMLCtx.position = 0;
+ XMLCtx.position2 = 0;
+ }
+
+ /* return results */
+ *attrs = XMLCtx.attrsGlobal;
+
+ if (XMLCtx.errDesc || XMLCtx.errCode) {
+ ctx->errDesc = XMLCtx.errDesc;
+ ctx->errCode = XMLCtx.errCode;
+ }
+
+ /* print all warning if corresponding env variable is set */
+ if (XMLCtx.warntxt && getenv("EDG_WLL_XML_WARNINGS")) {
+ fprintf(stderr,"----------------------------------------------------\n");
+ fprintf(stderr,"%s\n\n",XMLCtx.warntxt);
+ fprintf(stderr,"%s\n",messageBody);
+ fprintf(stderr,"----------------------------------------------------\n");
+ }
+
+ /* free parser */
+ XML_ParserFree(XMLCtx.p);
+
+ edg_wll_freeXMLCtx(&XMLCtx);
+ return errorCode;
+}
+
+
+
+/* parse notification result from client */
+edg_wll_ErrorCode edg_wll_ParseNotifResult(edg_wll_Context ctx, char *messageBody, time_t *validity)
+{
+ edg_wll_XML_ctx XMLCtx;
+ edg_wll_ErrorCode errorCode;
+ XML_Char *encoding = "ISO-8859-1";
+
+ errno = 0;
+ edg_wll_ResetError(ctx);
+ edg_wll_initXMLCtx(&XMLCtx);
+ XMLCtx.ctx = ctx;
+
+
+ /* initialize parser */
+ XMLCtx.p = XML_ParserCreate(encoding);
+ XML_SetElementHandler(XMLCtx.p, startNotifResult, endNotifResult);
+ XML_SetCharacterDataHandler(XMLCtx.p, char_handler);
+ XML_SetUserData(XMLCtx.p, (void *) &XMLCtx);
+
+
+ if (! XML_Parse(XMLCtx.p, messageBody, strlen(messageBody), 1)) {
+ char *errorMessage;
+
+ asprintf(&errorMessage, "Parse error at line %d:\n%s\n",
+ XML_GetCurrentLineNumber(XMLCtx.p),
+ XML_ErrorString(XML_GetErrorCode(XMLCtx.p)));
+
+ edg_wll_SetError(ctx, EDG_WLL_ERROR_XML_PARSE, errorMessage);
+ free(errorMessage);
+ } else if (XMLCtx.errtxt) edg_wll_SetError(ctx, EDG_WLL_ERROR_XML_PARSE, XMLCtx.errtxt);
+
+
+ if ((errorCode = edg_wll_Error(ctx,NULL,NULL))) {
+ *validity = -1;
+ } else {
+ *validity = XMLCtx.notifValidity;
+ }
+
+ if (XMLCtx.errDesc || XMLCtx.errCode) {
+ ctx->errDesc = XMLCtx.errDesc;
+ ctx->errCode = XMLCtx.errCode;
+ }
+
+ /* print all warning if corresponding env variable is set */
+ if (XMLCtx.warntxt && getenv("EDG_WLL_XML_WARNINGS")) {
+ fprintf(stderr,"----------------------------------------------------\n");
+ fprintf(stderr,"%s\n\n",XMLCtx.warntxt);
+ fprintf(stderr,"%s\n",messageBody);
+ fprintf(stderr,"----------------------------------------------------\n");
+ }
+
+ /* free parser */
+ XML_ParserFree(XMLCtx.p);
+
+ edg_wll_freeXMLCtx(&XMLCtx);
+ return errorCode;
+}
+
+
+
+
+/* construct Message-Body of Request-Line for edg_wll_QueryJobs */
+int edg_wll_JobQueryRecToXML(
+ edg_wll_Context ctx,
+ edg_wll_QueryRec const * const *conditions,
+ char **message)
+{
+ char *pomA, *pomB, *pomC;
+ int i = 0, len, tot_len = 0, nconditions, row = 0;
+ int *len_list;
+ char **list;
+
+
+ pomC = strdup("");
+
+ while (conditions && conditions[row]) {
+
+ pomA = pomB = NULL;
+
+ for (i=0; conditions[row][i].attr != EDG_WLL_QUERY_ATTR_UNDEF ; i++);
+ nconditions = i;
+
+ list = (char **) malloc ((nconditions) * sizeof(*list));
+ len_list = (int *) malloc ((nconditions) * sizeof(*len_list));
+
+ i=0;
+ while (i < nconditions) {
+ const char *pomOp;
+ char *pomValue;
+
+ asprintf(&pomValue,"%s","");
+
+ switch (conditions[row][i].attr) {
+ /* job specific conditions */
+ case EDG_WLL_QUERY_ATTR_JOBID:
+ edg_wll_add_jobid_to_XMLBody(&pomValue, conditions[row][i].value.j, "jobId", NULL);
+ break;
+ case EDG_WLL_QUERY_ATTR_TIME:
+ if (conditions[row][i].op == EDG_WLL_QUERY_OP_WITHIN) {
+ edg_wll_add_tagged_time_t_to_XMLBody(&pomValue, conditions[row][i].value.t.tv_sec, "time", edg_wll_StatToString(conditions[row][i].attr_id.state), "state", -1);
+ edg_wll_add_tagged_time_t_to_XMLBody(&pomValue, conditions[row][i].value2.t.tv_sec, "time", edg_wll_StatToString(conditions[row][i].attr_id.state), "state", -1);
+ }
+ else
+ edg_wll_add_tagged_time_t_to_XMLBody(&pomValue, conditions[row][i].value.t.tv_sec, "time", edg_wll_StatToString(conditions[row][i].attr_id.state), "state", -1);
+ break;
+
+ case EDG_WLL_QUERY_ATTR_PARENT:
+ edg_wll_add_jobid_to_XMLBody(&pomValue, conditions[row][i].value.j, "parent_job", NULL);
+ break;
+ case EDG_WLL_QUERY_ATTR_OWNER:
+ edg_wll_add_string_to_XMLBody(&pomValue, (conditions[row][i].value.c) ? conditions[row][i].value.c :
+ "NULL", "owner", NULL);
+ break;
+ case EDG_WLL_QUERY_ATTR_STATUS:
+ edg_wll_add_edg_wll_JobStatCode_to_XMLBody(&pomValue, conditions[row][i].value.i, "status", EDG_WLL_JOB_UNDEF);
+ if (conditions[row][i].op == EDG_WLL_QUERY_OP_WITHIN)
+ edg_wll_add_edg_wll_JobStatCode_to_XMLBody(&pomValue, conditions[row][i].value2.i, "status", EDG_WLL_JOB_UNDEF);
+ break;
+ case EDG_WLL_QUERY_ATTR_LOCATION:
+ edg_wll_add_string_to_XMLBody(&pomValue, conditions[row][i].value.c, "location", NULL);
+ break;
+ case EDG_WLL_QUERY_ATTR_DESTINATION:
+ edg_wll_add_string_to_XMLBody(&pomValue, conditions[row][i].value.c, "destination", NULL);
+ break;
+ case EDG_WLL_QUERY_ATTR_RESUBMITTED:
+ edg_wll_add_int_to_XMLBody(&pomValue, conditions[row][i].value.i, "resubmitted", -1);
+ if (conditions[row][i].op == EDG_WLL_QUERY_OP_WITHIN)
+ edg_wll_add_int_to_XMLBody(&pomValue, conditions[row][i].value2.i, "resubmitted", -1);
+ break;
+ case EDG_WLL_QUERY_ATTR_DONECODE:
+ edg_wll_add_int_to_XMLBody(&pomValue, conditions[row][i].value.i, "donecode", -1);
+ if (conditions[row][i].op == EDG_WLL_QUERY_OP_WITHIN)
+ edg_wll_add_int_to_XMLBody(&pomValue, conditions[row][i].value2.i, "donecode", -1);
+ break;
+ case EDG_WLL_QUERY_ATTR_EXITCODE:
+ edg_wll_add_int_to_XMLBody(&pomValue, conditions[row][i].value.i, "exitcode", -1);
+ if (conditions[row][i].op == EDG_WLL_QUERY_OP_WITHIN)
+ edg_wll_add_int_to_XMLBody(&pomValue, conditions[row][i].value2.i, "exitcode", -1);
+ break;
+ /* common conditions */
+ case EDG_WLL_QUERY_ATTR_USERTAG:
+ edg_wll_add_tagged_string_to_XMLBody(&pomValue, conditions[row][i].value.c, "usertag", conditions[row][i].attr_id.tag, "name", NULL);
+ break;
+ default:
+ free(pomValue);
+ return -1;
+ }
+ switch (conditions[row][i].op) {
+ case EDG_WLL_QUERY_OP_EQUAL: pomOp = "equal"; break;
+ case EDG_WLL_QUERY_OP_LESS: pomOp = "less"; break;
+ case EDG_WLL_QUERY_OP_GREATER: pomOp = "greater"; break;
+ case EDG_WLL_QUERY_OP_WITHIN: pomOp = "within"; break;
+ case EDG_WLL_QUERY_OP_UNEQUAL: pomOp = "unequal"; break;
+ default:
+ return -1;
+ }
+
+ len = asprintf(&list[i],"\t\t\t<%s>\n\t\t%s\t\t\t</%s>\r\n",
+ pomOp,pomValue,pomOp);
+ tot_len += len;
+ len_list[i] = len;
+
+ free(pomValue);
+
+ i++;
+ }
+
+
+ pomA = (char *) malloc(tot_len * sizeof(char) +
+ sizeof(QUERY_JOBS_OR_BEGIN) + sizeof(QUERY_JOBS_OR_END) - 1);
+
+ memcpy(pomA, QUERY_JOBS_OR_BEGIN, sizeof(QUERY_JOBS_OR_BEGIN));
+ pomB = pomA + sizeof(QUERY_JOBS_OR_BEGIN) - 1;
+
+ for (i=0; i < nconditions; i++) {
+ memcpy(pomB, list[i], len_list[i] );
+ pomB += len_list[i];
+ free(list[i]);
+ }
+ free(list);
+ free(len_list);
+
+ strcpy(pomB, QUERY_JOBS_OR_END);
+ asprintf(message,"%s%s", pomC, pomA);
+ free(pomA);
+ free(pomC);
+ pomC = *message;
+ *message = NULL;
+
+ row++;
+ }
+
+
+ asprintf(message,"%s", pomC);
+
+ free(pomC);
+
+ return 0;
+}
+
+
+
+
+/* construct Message-Body of Request-Line for edg_wll_QueryEvents */
+int edg_wll_QueryEventsRequestToXML(
+ edg_wll_Context ctx,
+ const edg_wll_QueryRec **job_conditions,
+ const edg_wll_QueryRec **event_conditions,
+ char **message)
+{
+ char *pomA, *pomB, *pomC;
+ int i = 0, len, tot_len = 0, row = 0;
+ int nevent_conditions;
+ char **list;
+ int *len_list;
+
+
+ edg_wll_JobQueryRecToXML(ctx, job_conditions, &pomC);
+
+ row = 0;
+ while(event_conditions && event_conditions[row]) {
+
+ pomA = pomB = NULL;
+
+ for (i=0; event_conditions[row][i].attr != EDG_WLL_QUERY_ATTR_UNDEF ; i++);
+ nevent_conditions = i;
+
+ list = (char **) malloc ((nevent_conditions) * sizeof(*list));
+ len_list = (int *) malloc ((nevent_conditions) * sizeof(*len_list));
+
+ i=0;
+ while (i < nevent_conditions) {
+ const char *pomOp;
+ char *pomValue;
+
+ asprintf(&pomValue,"%s","");
+
+ switch (event_conditions[row][i].attr) {
+ /* event specific conditions */
+ case EDG_WLL_QUERY_ATTR_TIME:
+ if (event_conditions[row][i].op == EDG_WLL_QUERY_OP_WITHIN) {
+ edg_wll_add_tagged_time_t_to_XMLBody(&pomValue, event_conditions[row][i].value.t.tv_sec, "time", edg_wll_StatToString(event_conditions[row][i].attr_id.state), "state", -1);
+ edg_wll_add_tagged_time_t_to_XMLBody(&pomValue, event_conditions[row][i].value2.t.tv_sec, "time", edg_wll_StatToString(event_conditions[row][i].attr_id.state), "state", -1);
+ }
+ else
+ edg_wll_add_tagged_time_t_to_XMLBody(&pomValue, event_conditions[row][i].value.t.tv_sec, "time", edg_wll_StatToString(event_conditions[row][i].attr_id.state), "state", -1);
+ break;
+ case EDG_WLL_QUERY_ATTR_LEVEL:
+ edg_wll_add_int_to_XMLBody(&pomValue, event_conditions[row][i].value.i, "level", -1);
+ if (event_conditions[row][i].op == EDG_WLL_QUERY_OP_WITHIN)
+ edg_wll_add_int_to_XMLBody(&pomValue, event_conditions[row][i].value2.i, "level", -1);
+ break;
+ case EDG_WLL_QUERY_ATTR_HOST:
+ edg_wll_add_string_to_XMLBody(&pomValue, event_conditions[row][i].value.c, "host", NULL);
+ break;
+ case EDG_WLL_QUERY_ATTR_SOURCE:
+ edg_wll_add_int_to_XMLBody(&pomValue, event_conditions[row][i].value.i, "source", -1);
+ break;
+ case EDG_WLL_QUERY_ATTR_INSTANCE:
+ edg_wll_add_string_to_XMLBody(&pomValue, event_conditions[row][i].value.c, "instance", NULL);
+ break;
+ case EDG_WLL_QUERY_ATTR_EVENT_TYPE:
+ edg_wll_add_int_to_XMLBody(&pomValue, event_conditions[row][i].value.i, "type", EDG_WLL_EVENT_UNDEF);
+ if (event_conditions[row][i].op == EDG_WLL_QUERY_OP_WITHIN)
+ edg_wll_add_int_to_XMLBody(&pomValue, event_conditions[row][i].value2.i, "type", EDG_WLL_EVENT_UNDEF);
+ break;
+ /* common conditions */
+ case EDG_WLL_QUERY_ATTR_USERTAG:
+ edg_wll_add_tagged_string_to_XMLBody(&pomValue, event_conditions[row][i].value.c, "usertag", event_conditions[row][i].attr_id.tag, "name", NULL);
+ break;
+ default:
+ free(pomValue);
+ return -1;
+ }
+ switch (event_conditions[row][i].op) {
+ case EDG_WLL_QUERY_OP_EQUAL: pomOp = "equal"; break;
+ case EDG_WLL_QUERY_OP_LESS: pomOp = "less"; break;
+ case EDG_WLL_QUERY_OP_GREATER: pomOp = "greater"; break;
+ case EDG_WLL_QUERY_OP_WITHIN: pomOp = "within"; break;
+ case EDG_WLL_QUERY_OP_UNEQUAL: pomOp = "unequal"; break;
+ default:
+ return -1;
+ }
+
+ len = asprintf(&list[i],"\t\t\t<%s>\n\t\t%s\t\t\t</%s>\r\n",
+ pomOp,pomValue,pomOp);
+
+ tot_len += len;
+ len_list[i] = len;
+
+ free(pomValue);
+
+ i++;
+ }
+
+ pomA = (char *) malloc(tot_len * sizeof(char) +
+ sizeof(QUERY_EVENTS_OREC_BEGIN) + sizeof(QUERY_EVENTS_OREC_END) - 1);
+
+ memcpy(pomA, QUERY_EVENTS_OREC_BEGIN, sizeof(QUERY_EVENTS_OREC_BEGIN));
+ pomB = pomA + sizeof(QUERY_EVENTS_OREC_BEGIN) - 1;
+
+ for (i=0; i < nevent_conditions; i++) {
+ memcpy(pomB, list[i], len_list[i] );
+ pomB += len_list[i];
+ free(list[i]);
+ }
+ free(list);
+ free(len_list);
+
+ strcpy(pomB, QUERY_EVENTS_OREC_END);
+ asprintf(message,"%s%s", pomC, pomA);
+ free(pomA);
+ free(pomC);
+ pomC = *message;
+ *message = NULL;
+
+ row++;
+ }
+
+ asprintf(message,"%s softLimit=\"%d\" queryRes=\"%d\">\r\n\t<and>\r\n%s%s",
+ QUERY_EVENTS_REQUEST_BEGIN,
+ ctx->p_query_events_limit, ctx->p_query_results,
+ pomC, QUERY_EVENTS_REQUEST_END);
+
+ free(pomC);
+
+ return 0;
+}
+
+
+
+/* construct Message-Body of Request-Line for edg_wll_QueryJobs */
+int edg_wll_QueryJobsRequestToXML(
+ edg_wll_Context ctx,
+ const edg_wll_QueryRec **conditions,
+ int flags,
+ char **message)
+{
+ char *pomC, *cflags;
+
+
+ edg_wll_JobQueryRecToXML(ctx, conditions, &pomC);
+
+ asprintf(message,
+ "%s softLimit=\"%d\" queryRes=\"%d\">\r\n\t<flags>%s</flags>\r\n\t<and>\r\n%s%s",
+ QUERY_JOBS_REQUEST_BEGIN,
+ ctx->p_query_jobs_limit, ctx->p_query_results,
+ cflags = edg_wll_stat_flags_to_string(flags), pomC, QUERY_JOBS_REQUEST_END);
+
+ free(cflags);
+ free(pomC);
+
+ return 0;
+}
+
+
+/* construct Message-Body of Request-Line for edg_wll_Purge */
+int edg_wll_PurgeRequestToXML(
+ edg_wll_Context ctx,
+ const edg_wll_PurgeRequest *request,
+ char **message)
+{
+ char *pomA, *pomB, *pomC;
+
+
+ if (!request) { *message = NULL; return(-1); }
+
+ pomA = strdup("");
+ if (request->jobs) edg_wll_add_strlist_to_XMLBody(&pomA, request->jobs, "jobs",
+ "jobId", "\t", NULL);
+
+ /* print timeout for all status codes */
+ pomB = strdup("");
+ edg_wll_add_time_t_list_to_XMLBody(&pomB, request->timeout, "timeout", edg_wll_StatToString, "\t",
+ 0, EDG_WLL_NUMBER_OF_STATCODES);
+
+ trio_asprintf(&pomC,"%s%s%s\t<flags>%|Xs</flags>\r\n%s",
+ PURGE_REQUEST_BEGIN,pomA,pomB,edg_wll_purge_flags_to_string(request->flags),
+ PURGE_REQUEST_END);
+
+ free(pomA);
+ free(pomB);
+
+
+ *message = pomC;
+
+ return 0;
+}
+
+
+
+/* construct Message-Body of Request-Line for edg_wll_Dump */
+int edg_wll_DumpRequestToXML(
+ edg_wll_Context ctx,
+ const edg_wll_DumpRequest *request,
+ char **message)
+{
+ char *pomA, *pomB;
+
+
+ if (!request) { *message = NULL; return(-1); }
+
+ pomA = strdup("");
+ if (request->from < 0)
+ edg_wll_add_string_to_XMLBody(&pomA,
+ edg_wll_DumpConstToString(request->from), "from", NULL);
+ else
+ edg_wll_add_time_t_to_XMLBody(&pomA, request->from, "from", 0);
+ if (request->to < 0)
+ edg_wll_add_string_to_XMLBody(&pomA,
+ edg_wll_DumpConstToString(request->to), "to", NULL);
+ else
+ edg_wll_add_time_t_to_XMLBody(&pomA, request->to, "to", 0);
+
+ trio_asprintf(&pomB,"%s%s%s",
+ DUMP_REQUEST_BEGIN,pomA,DUMP_REQUEST_END);
+
+ free(pomA);
+
+
+ *message = pomB;
+
+ return 0;
+}
+
+
+
+/* construct Message-Body of Request-Line for edg_wll_Load */
+int edg_wll_LoadRequestToXML(
+ edg_wll_Context ctx,
+ const edg_wll_LoadRequest *request,
+ char **message)
+{
+ char *pomA, *pomB;
+
+
+ if (!request) { *message = NULL; return(-1); }
+
+ pomA = strdup("");
+ edg_wll_add_string_to_XMLBody(&pomA, request->server_file, "server_file", 0);
+
+ trio_asprintf(&pomB,"%s%s%s",
+ LOAD_REQUEST_BEGIN,pomA,LOAD_REQUEST_END);
+
+ free(pomA);
+
+
+ *message = pomB;
+
+ return 0;
+}
+
+
+
+/* construct Message-Body of Request-Line for edg_wll_IndexedAttrs */
+int edg_wll_IndexedAttrsRequestToXML(
+ edg_wll_Context ctx,
+ char **message)
+{
+ char *pomB;
+
+
+ trio_asprintf(&pomB,"%s%s",
+ INDEXED_ATTRS_REQUEST_BEGIN,INDEXED_ATTRS_REQUEST_END);
+
+ *message = pomB;
+
+ return 0;
+}
+
+
+/* construct Message-Body of Request-Line for edg_wll_Notif* functions */
+int edg_wll_NotifRequestToXML(
+ edg_wll_Context ctx,
+ const char *function,
+ const edg_wll_NotifId notifId,
+ const char *address,
+ edg_wll_NotifChangeOp op,
+ edg_wll_QueryRec const * const *conditions,
+ char **message)
+{
+ char *pomA=NULL, *pomB=NULL, *pomC=NULL;
+
+
+ pomA = strdup("");
+ edg_wll_add_string_to_XMLBody(&pomA, edg_wll_NotifIdUnparse(notifId), "notifId", NULL);
+ edg_wll_add_string_to_XMLBody(&pomA, address, "clientAddress", NULL);
+ edg_wll_add_int_to_XMLBody(&pomA, op, "notifChangeOp", EDG_WLL_NOTIF_NOOP);
+ if (conditions && conditions[0] && conditions[0][0].attr != EDG_WLL_QUERY_ATTR_UNDEF)
+ edg_wll_JobQueryRecToXML(ctx, conditions, &pomB);
+
+
+ if (pomB)
+ trio_asprintf(&pomC,"%s function=\"%s\">\r\n%s\t<and>\r\n%s\t</and>\r\n%s",
+ NOTIF_REQUEST_BEGIN,function,pomA,pomB,NOTIF_REQUEST_END);
+ else
+ trio_asprintf(&pomC,"%s function=\"%s\">\r\n%s%s",
+ NOTIF_REQUEST_BEGIN,function,pomA,NOTIF_REQUEST_END);
+
+
+ free(pomA);
+ free(pomB);
+ *message = pomC;
+
+ return 0;
+}
--- /dev/null
+include Makefile.inc
+
+YACC=bison -y
+
+VPATH:=${src}
+AT3:=perl -I${lbconfig} ${lbproject}/at3
+SUFFIXES = .T
+
+DEBUG:=-g -O0
+CFLAGS:=${DEBUG} -I${stageinc} -I${src} -I. \
+ -I${repository}/${voms}/include \
+ -I${repository}/${gacl}/include \
+ -I${repository}/${expat}/include \
+ -I${repository}/${mysql}/include \
+ -I/usr/include/libxml2 \
+ -I${repository}/${globus}/include/${globusflavour} \
+ -I${repository}/${globus}/include/${globusflavour}/openssl
+
+LINK:=libtool --mode=link ${CC} ${LDFLAGS}
+INSTALL:=libtool --mode=install install
+
+# assisst & gss due to VOMS only
+
+GLOBUS_LIBS:= -L${repository}/${globus}/lib \
+ -lglobus_gss_assist_${globusflavour} \
+ -lglobus_gssapi_gsi_${globusflavour} \
+ -lglobus_common_${globusflavour} \
+ -lssl_${globusflavour}
+
+
+# XXX: our vomsc.la depends on badly installed expat
+
+EXT_LIBS:= -L${repository}/${ares}/lib -lares \
+ -L${repository}/${mysql}/lib -lmysqlclient \
+ -L${repository}/${gacl}/lib -lgacl \
+ ${repository}/${voms}/lib/libvomsc.a \
+ -L${repository}/${expat}/lib -lexpat \
+ ${GLOBUS_LIBS}
+
+COMMON_LIB:= -L${stagelib} -lglite_lb_common
+
+HELPERS:= -L${stagelib} -lglite_wms_tls_ssl_helpers
+
+
+SERVER_OBJS:= bkserverd.o get_events.o index.o jobstat.o jobstat_supp.o \
+ write2rgma.o lbs_db.o lb_html.o lb_http.o lb_proto.o lb_xml_parse.o \
+ lock.o openserver.o query.o userjobs.o db_store.o request.o store.o \
+ stored_master.o srv_purge.o server_state.o dump.o lb_authz.o load.o \
+ notification.o il_notification.o notif_match.o
+
+INDEX_OBJS:= index.o index_parse.o jobstat_supp.o lbs_db.o openserver.o \
+ jobstat.o query.o lock.o get_events.o write2rgma.o index_lex.o \
+ lb_authz.o store.o bkindex.o
+
+default: stage
+
+compile: glite_lb_bkserverd glite_lb_bkindex
+
+glite_lb_bkserverd: ${SERVER_OBJS}
+ ${LINK} -o $@ ${SERVER_OBJS} ${COMMON_LIB} ${HELPERS} ${EXT_LIBS}
+
+glite_lb_bkindex: ${INDEX_OBJS}
+ ${LINK} -o $@ ${INDEX_OBJS} ${COMMON_LIB} ${HELPERS} ${EXT_LIBS}
+
+all stage export: compile
+ ${INSTALL} -m 755 glite_lb_bkserverd glite_lb_bkindex ${stagebin}
+
+
+%.c: %.c.T
+ rm -f $@
+ ${AT3} $< >$@ || rm -f $@
+ chmod -w $@ >/dev/null
+
+%.o: %.y
+ ${YACC} -d ${YFLAGS} $<
+ mv y.tab.c $*.c
+ mv y.tab.h $*.h
+ ${CC} -c ${CFLAGS} $*.c
+ rm $*.c
--- /dev/null
+<?xml version="1.0" encoding="UTF-8" ?>
+
+<project name="lb" default="dist">
+
+ <import file="../org.glite/project/baseline.properties.xml" />
+ <import file="./project/properties.xml"/>
+ <import file="${subsystem.properties.file}"/>
+ <import file="${global.properties.file}" />
+
+ <property file="${user.dependencies.file}"/>
+ <property file="${component.dependencies.file}" />
+ <property file="${subsystem.dependencies.file}" />
+ <property file="${global.dependencies.file}"/>
+
+ <import file="${subsystem.taskdefs.file}" />
+ <import file="${global.taskdefs.file}" />
+
+ <import file="${global.targets-external-dependencies.file}"/>
+ <import file="${global.targets-make.file}" />
+
+ <property file="${module.version.file}"/>
+
+ <target name="localinit"
+ description="Module specific initialization tasks">
+ <antcall target="lbmakefiles"/>
+ </target>
+
+ <target name="localcompile"
+ description="Module specific compile tasks">
+ </target>
+
+ <target name="localclean"
+ description="Module specific cleaning tasks">
+ </target>
+
+</project>
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+
+<project name="LB server component common properties">
+
+ <property file="build.properties" />
+ <property name="subsystem.name" value="${lb.subsystem.name}"/>
+ <property name="subsystem.prefix" value="${lb.subsystem.prefix}"/>
+ <property name="component.prefix" value="server" />
+
+ <import file="${component.general.properties.file}" />
+
+</project>
--- /dev/null
+#ident "$Header$"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <getopt.h>
+#include <sysexits.h>
+#include <assert.h>
+
+#include "glite/wms/jobid/strmd5.h"
+#include "glite/lb/consumer.h"
+#include "glite/lb/context-int.h"
+#include "index.h"
+#include "lbs_db.h"
+#include "jobstat.h"
+
+static struct option opts[] = {
+ { "mysql",1,NULL,'m' },
+ { "remove",0,NULL,'R' },
+ { "really",0,NULL,'r' },
+ { "dump",0,NULL,'d' },
+ { "verbose",0,NULL,'v' },
+ { NULL, 0, NULL, 0 }
+};
+
+static void usage(const char *);
+static void do_exit(edg_wll_Context,int);
+static char *col_list(const edg_wll_QueryRec *);
+static char *db_col_type(const edg_wll_QueryRec *);
+
+/* XXX: don't bother with malloc() of arrays that are tiny in real life */
+#define CI_MAX 200
+
+int debug;
+
+int main(int argc,char **argv)
+{
+ int opt;
+ char *dbstring = getenv("LBDB");
+ char *fname = "-";
+ int dump = 0, really = 0, verbose = 0, remove_all = 0;
+ edg_wll_Context ctx;
+ edg_wll_QueryRec **old_indices,**new_indices;
+ edg_wll_QueryRec *new_columns[CI_MAX],*old_columns[CI_MAX];
+ int add_columns[CI_MAX],drop_columns[CI_MAX];
+ int add_indices[CI_MAX],drop_indices[CI_MAX];
+ edg_wll_IColumnRec *added_icols;
+ int nadd_icols;
+ char **index_names;
+ int i,j,k;
+ int nnew,nold,nadd,ndrop;
+ char *stmt;
+
+ for (i=0; i<CI_MAX; i++) add_indices[i] = drop_indices[i] = -1;
+ memset(new_columns,0,sizeof new_columns);
+ memset(old_columns,0,sizeof old_columns);
+ memset(add_columns,0,sizeof add_columns);
+ memset(drop_columns,0,sizeof drop_columns);
+
+ while ((opt = getopt_long(argc,argv,"m:rRdv",opts,NULL)) != EOF) switch (opt) {
+ case 'm': dbstring = optarg; break;
+ case 'r': really = 1; break;
+ case 'R': remove_all = 1; break;
+ case 'd': dump = 1; break;
+ case 'v': verbose++; break;
+ case '?': usage(argv[0]); exit(EX_USAGE);
+ }
+
+ if (really && dump) { usage(argv[0]); exit(EX_USAGE); }
+ if (really && remove_all) { usage(argv[0]); exit(EX_USAGE); }
+ if (optind < argc) {
+ if (dump || remove_all) { usage(argv[0]); exit(EX_USAGE); }
+ else fname = argv[optind];
+ }
+
+ edg_wll_InitContext(&ctx);
+ if (edg_wll_Open(ctx,dbstring)) do_exit(ctx,EX_UNAVAILABLE);
+ if (edg_wll_DBCheckVersion(ctx)) do_exit(ctx,EX_SOFTWARE);
+ if (edg_wll_QueryJobIndices(ctx,&old_indices,&index_names)) do_exit(ctx,EX_SOFTWARE);
+
+ if (dump) {
+ if (edg_wll_DumpIndexConfig(ctx,fname,old_indices)) do_exit(ctx,EX_SOFTWARE);
+ else if ( !remove_all ) return 0;
+ }
+
+ if (remove_all) {
+ if (verbose) printf("Dropping all indices");
+ for (i=0; index_names && index_names[i]; i++) {
+ asprintf(&stmt,"alter table states drop index `%s`",index_names[i]);
+ if (verbose) putchar('.');
+ if (edg_wll_ExecStmt(ctx,stmt,NULL) < 0) do_exit(ctx,EX_SOFTWARE);
+ free(stmt);
+ }
+ if (verbose) puts(" done");
+ if (verbose) printf("Dropping index columns");
+ for (i=0; old_indices && old_indices[i]; i++) {
+ char *cname = edg_wll_QueryRecToColumn(old_indices[i]);
+ asprintf(&stmt,"alter table states drop column `%s`",cname);
+ if (verbose) putchar('.');
+ if (edg_wll_ExecStmt(ctx,stmt,NULL) < 0) do_exit(ctx,EX_SOFTWARE);
+ free(stmt);
+ free(cname);
+ }
+ if (verbose) puts(" done");
+ return 0;
+ }
+
+ if (edg_wll_ParseIndexConfig(ctx,fname,&new_indices))
+ do_exit(ctx,edg_wll_Error(ctx,NULL,NULL) == EINVAL ? EX_DATAERR : EX_IOERR);
+
+ /* FIXME: check duplicate columns in indices */
+
+/* indices to add & drop */
+ nadd = ndrop = 0;
+ if (old_indices && new_indices) {
+ for (i=0; old_indices[i]; i++) {
+ for (j=0; new_indices[j]; j++) {
+ for (k=0; old_indices[i][k].attr &&
+ !edg_wll_CmpColumn(&old_indices[i][k],&new_indices[j][k]);
+ k++);
+ if (!old_indices[i][k].attr && !new_indices[j][k].attr) break;
+ }
+ if (!new_indices[j]) drop_indices[ndrop++] = i;
+ }
+
+ for (i=0; new_indices[i]; i++) {
+ for (j=0; old_indices[j]; j++) {
+ for (k=0; new_indices[i][k].attr &&
+ !edg_wll_CmpColumn(&new_indices[i][k],&old_indices[j][k]);
+ k++);
+ if (!new_indices[i][k].attr && !old_indices[j][k].attr) break;
+ }
+ if (!old_indices[j]) add_indices[nadd++] = i;
+ }
+ }
+ else if (new_indices) for (i=0; new_indices[i]; i++) add_indices[i] = i;
+ else if (old_indices) for (i=0; old_indices[i]; i++) drop_indices[i] = i;
+
+/* old and new column sets */
+ nold = nnew = 0;
+ if (old_indices) for (i=0; old_indices[i]; i++)
+ for (j=0; old_indices[i][j].attr; j++) {
+ for (k=0; k<nold && edg_wll_CmpColumn(old_columns[k],&old_indices[i][j]); k++);
+ if (k == nold) {
+ assert(nold < CI_MAX);
+ old_columns[nold++] = &old_indices[i][j];
+ }
+ }
+
+ if (new_indices) for (i=0; new_indices[i]; i++)
+ for (j=0; new_indices[i][j].attr; j++) {
+ for (k=0; k<nnew && edg_wll_CmpColumn(new_columns[k],&new_indices[i][j]); k++);
+ if (k == nnew) {
+ assert(nnew < CI_MAX);
+ new_columns[nnew++] = &new_indices[i][j];
+ }
+ }
+
+/* go! */
+ if (!really) puts("\n** Dry run, no actual actions performed **\n");
+
+ if (verbose) puts("Dropping indices ...");
+ for (i=0; drop_indices[i] >= 0; i++) {
+ if (verbose) {
+ char *n = col_list(old_indices[drop_indices[i]]);
+ printf("\t%s(%s) ... ",index_names[drop_indices[i]],n); fflush(stdout);
+ free(n);
+ }
+ if (really) {
+ asprintf(&stmt,"alter table states drop index `%s`",index_names[drop_indices[i]]);
+ if (edg_wll_ExecStmt(ctx,stmt,NULL) < 0) do_exit(ctx,EX_SOFTWARE);
+ free(stmt);
+ }
+ if (verbose) puts(really ? "done" : "");
+ }
+
+ if (verbose) puts("Dropping columns ...");
+ for (i=0; i<nold; i++) {
+ for (j=0; j<nnew && edg_wll_CmpColumn(old_columns[i],new_columns[j]); j++);
+ if (j == nnew) {
+ char *cname = edg_wll_QueryRecToColumn(old_columns[i]);
+ if (verbose) printf("\t%s\n",cname);
+ if (really) {
+ asprintf(&stmt,"alter table states drop column `%s`",cname);
+ if (edg_wll_ExecStmt(ctx,stmt,NULL) < 0) do_exit(ctx,EX_SOFTWARE);
+ free(stmt);
+ }
+ free(cname);
+ }
+ }
+
+ added_icols = calloc(nnew+1, sizeof(edg_wll_IColumnRec));
+ nadd_icols = 0;
+ if (verbose) puts("Adding columns ...");
+ for (i=0; i<nnew; i++) {
+ for (j=0; j<nold && edg_wll_CmpColumn(new_columns[i],old_columns[j]); j++);
+ if (j == nold) {
+ char *cname = edg_wll_QueryRecToColumn(new_columns[i]);
+ if (verbose) printf("\t%s\n",cname);
+ if (really) {
+ char *ctype = db_col_type(new_columns[i]);
+ asprintf(&stmt,"alter table states add `%s` %s",cname,ctype);
+ if (edg_wll_ExecStmt(ctx,stmt,NULL) < 0) do_exit(ctx,EX_SOFTWARE);
+ free(stmt);
+ }
+ memcpy(&added_icols[nadd_icols].qrec, new_columns[i], sizeof(edg_wll_QueryRec));
+ added_icols[nadd_icols].colname = strdup(cname);
+ if (new_columns[i]->attr == EDG_WLL_QUERY_ATTR_USERTAG)
+ added_icols[nadd_icols].qrec.attr_id.tag =
+ strdup(new_columns[i]->attr_id.tag);
+ nadd_icols++;
+ free(cname);
+ }
+ }
+
+ if (nadd_icols) {
+ added_icols[nadd_icols].qrec.attr = EDG_WLL_QUERY_ATTR_UNDEF;
+ added_icols[nadd_icols].colname = NULL;
+ if (verbose) puts("Refreshing data ...");
+ if (really && edg_wll_RefreshIColumns(ctx, (void*) added_icols)) do_exit(ctx,EX_SOFTWARE);
+ }
+ else if (verbose) puts("No data refresh required");
+
+ for (nadd_icols--; nadd_icols >= 0; nadd_icols--)
+ edg_wll_FreeIColumnRec(&added_icols[nadd_icols]);
+ free(added_icols);
+
+ if (verbose) puts("Creating indices ...");
+ for (i=0; add_indices[i] >= 0; i++) {
+ char *l = col_list(new_indices[add_indices[i]]);
+ char *n = str2md5base64(l);
+ if (verbose) { printf("\t%s(%s) ... ",n,l); fflush(stdout); }
+ if (really) {
+ asprintf(&stmt,"create index `%s` on states(%s)",n,l);
+ free(n); free(l);
+ if (edg_wll_ExecStmt(ctx,stmt,NULL) < 0) do_exit(ctx,EX_SOFTWARE);
+ free(stmt);
+ }
+ if (verbose) puts(really ? "done" : "");
+ }
+
+ return 0;
+}
+
+static char *col_list(const edg_wll_QueryRec *ind)
+{
+ char *ret,*aux,size[50] = "";
+ int j;
+
+ aux = edg_wll_QueryRecToColumn(ind);
+ if (ind->value.i) sprintf(size,"(%d)",ind->value.i);
+ asprintf(&ret,"`%s`%s",aux,size);
+ free(aux);
+
+ for (j=1; ind[j].attr; j++) {
+ char *n = edg_wll_QueryRecToColumn(ind+j),size[50] = "";
+ if (ind[j].value.i) sprintf(size,"(%d)",ind[j].value.i);
+ aux = ret;
+ asprintf(&ret,"%s,`%s`%s",aux,n,size);
+ free(n); free(aux);
+ }
+ return ret;
+}
+
+static char *db_col_type(const edg_wll_QueryRec *r)
+{
+ switch (r->attr) {
+ case EDG_WLL_QUERY_ATTR_OWNER:
+ case EDG_WLL_QUERY_ATTR_LOCATION:
+ case EDG_WLL_QUERY_ATTR_DESTINATION:
+ case EDG_WLL_QUERY_ATTR_USERTAG:
+ case EDG_WLL_QUERY_ATTR_HOST:
+ case EDG_WLL_QUERY_ATTR_CHKPT_TAG:
+ return "char(250) binary null";
+
+ case EDG_WLL_QUERY_ATTR_TIME:
+ return "datetime null";
+ default:
+ return NULL;
+ }
+}
+
+static void do_exit(edg_wll_Context ctx,int code)
+{
+ char *et,*ed;
+
+ edg_wll_Error(ctx,&et,&ed);
+ fprintf(stderr,"edg-bkindex: %s (%s)\n",et,ed);
+ exit(code);
+}
+
+static void usage(const char *me)
+{
+ fprintf(stderr,"usage: %s <options> [file]\n"
+ " -m,--mysql <dbstring> use non-default database connection\n"
+ " -r,--really really perform reindexing\n"
+ " -R,--remove remove all indexes from server\n"
+ " -d,--dump dump current setup\n"
+ " -v,--verbose increase verbosity (2 levels)\n"
+ "\n -r and -d are mutually exlusive\n"
+ "\n -r and -R are mutually exlusive\n"
+ " [file] is applicable only without -d and -R\n",
+ me);
+}
--- /dev/null
+#ident "$Header$"
+
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <getopt.h>
+#include <linux/limits.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <sys/wait.h>
+#include <sys/socket.h>
+#include <sys/uio.h>
+#include <netinet/in.h>
+#include <signal.h>
+#include <errno.h>
+#include <netdb.h>
+#include <limits.h>
+#include <assert.h>
+#include <syslog.h>
+#include <sys/time.h>
+#include <arpa/inet.h>
+#include <arpa/nameser.h>
+#include <resolv.h>
+#include <ares.h>
+#include <sys/ipc.h>
+#include <sys/sem.h>
+
+#include <globus_common.h>
+
+#include "glite/wms/tls/ssl_helpers/ssl_inits.h"
+#include "glite/lb/consumer.h"
+#include "glite/lb/purge.h"
+#include "glite/lb/context.h"
+#include "glite/lb/mini_http.h"
+#include "lb_http.h"
+#include "lb_proto.h"
+#include "index.h"
+#include "lbs_db.h"
+#include "lb_authz.h"
+#include "il_notification.h"
+
+extern int edg_wll_StoreProto(edg_wll_Context ctx);
+extern edg_wll_ErrorCode edg_wll_Open(edg_wll_Context ctx, char *cs);
+edg_wll_ErrorCode edg_wll_Close(edg_wll_Context);
+
+#define max(x,y) ((x)>(y)?(x):(y))
+
+#define CON_QUEUE 20 /* accept() */
+#define SLAVE_OVERLOAD 10 /* queue items per slave */
+#define CLNT_TIMEOUT 10 /* keep idle connection that many seconds */
+#define TOTAL_CLNT_TIMEOUT 60 /* one client may ask one slave multiple times */
+ /* but only limited time to avoid DoS attacks */
+#define CLNT_REJECT_TIMEOUT 100000 /* time limit for client rejection in !usec! */
+#define DNS_TIMEOUT 5 /* how long wait for DNS lookup */
+#define SLAVE_CONNS_MAX 500 /* commit suicide after that many connections */
+#define MASTER_TIMEOUT 30 /* maximal time of one-round of master network communication */
+#define SLAVE_TIMEOUT 30 /* maximal time of one-round of slave network communication */
+#define SLAVE_CHECK_SIGNALS 2 /* how often to check signals while waiting for recv_mesg */
+#define WATCH_TIMEOUT 1800 /* wake up to check updated credentials */
+
+#ifndef EDG_PURGE_STORAGE
+#define EDG_PURGE_STORAGE "/tmp/purge"
+#endif
+
+#ifndef EDG_DUMP_STORAGE
+#define EDG_DUMP_STORAGE "/tmp/dump"
+#endif
+
+/* file to store pid and generate semaphores key */
+#ifndef EDG_BKSERVERD_PIDFILE
+#define EDG_BKSERVERD_PIDFILE "/var/run/edg-bkserverd.pid"
+#endif
+
+#ifndef dprintf
+#define dprintf(x) { if (debug) printf x; }
+#endif
+
+ static const int one = 1;
+
+int debug = 0;
+int rgma_export = 0;
+static int noAuth = 0;
+static int noIndex = 0;
+static int strict_locking = 0;
+static int hardJobsLimit = 0;
+static int hardEventsLimit = 0;
+static int hardRespSizeLimit = 0;
+static char *dbstring = NULL,*fake_host = NULL;
+static int fake_port = 0;
+
+static char ** super_users = NULL;
+char *cadir = NULL, *vomsdir = NULL;
+
+
+static int slaves = 10, semaphores = -1, semset;
+static char *purgeStorage = EDG_PURGE_STORAGE;
+static char *dumpStorage = EDG_DUMP_STORAGE;
+static time_t purge_timeout[EDG_WLL_NUMBER_OF_STATCODES];
+static time_t notif_duration = 60*60*24*7;
+static edg_wll_QueryRec **job_index;
+static edg_wll_IColumnRec *job_index_cols;
+
+static volatile int die = 0, child_died = 0;
+
+static int dispatchit(int,int,int);
+static int do_sendmsg(int,int,unsigned long,int);
+static int do_recvmsg(int,int *,unsigned long *,int *);
+
+static void wait_for_open(edg_wll_Context,const char *);
+
+static void catchsig(int sig)
+{
+ die = sig;
+}
+
+static void catch_chld(int sig)
+{
+ child_died = 1;
+}
+
+static int slave(void *,int);
+
+static struct option opts[] = {
+ {"cert", 1, NULL, 'c'},
+ {"key", 1, NULL, 'k'},
+ {"CAdir", 1, NULL, 'C'},
+ {"VOMSdir", 1, NULL, 'V'},
+ {"port", 1, NULL, 'p'},
+ {"address", 1, NULL, 'a'},
+ {"debug", 0, NULL, 'd'},
+ {"rgmaexport", 0, NULL, 'r'},
+ {"mysql", 1, NULL, 'm'},
+ {"noauth", 0, NULL, 'n'},
+ {"slaves", 1, NULL, 's'},
+ {"semaphores", 1, NULL, 'l'},
+ {"pidfile", 1, NULL, 'i'},
+ {"purge-prefix", 1, NULL, 'S'},
+ {"dump-prefix", 1, NULL, 'D'},
+ {"super-user", 1, NULL, 'R'},
+ {"super-users-file", 1, NULL,'F'},
+ {"no-index", 1, NULL, 'x'},
+ {"strict-locking",0, NULL, 'P'},
+ {"limits", 1, NULL, 'L'},
+ {"notif-dur", 1, NULL, 'N'},
+ {"notif-il-sock", 1, NULL, 'X'},
+ {NULL,0,NULL,0}
+};
+
+static void usage(char *me)
+{
+ fprintf(stderr,"usage: %s [option]\n"
+ "\t-a, --address\t use this server address (may be faked for debugging)\n"
+ "\t-k, --key\t private key file\n"
+ "\t-c, --cert\t certificate file\n"
+ "\t-C, --CAdir\t trusted certificates directory\n"
+ "\t-V, --VOMSdir\t trusted VOMS servers certificates directory\n"
+ "\t-p, --port\t port to listen\n"
+ "\t-m, --mysql\t database connect string\n"
+ "\t-d, --debug\t don't run as daemon, additional diagnostics\n"
+ "\t-r, --rgmaexport write state info to RGMA interface\n"
+ "\t-n, --noauth\t don't check user identity with result owner\n"
+ "\t-s, --slaves\t number of slave servers to fork\n"
+ "\t-l, --semaphores number of semaphores (job locks) to use\n"
+ "\t-i, --pidfile\t file to store master pid\n"
+ "\t-L, --limits\t query limits numbers in format \"events_limit:jobs_limit:size_limit\"\n"
+ "\t-N, --notif-dur\t Maximal duration of notification registrations in hours\n"
+ "\t-S, --purge-prefix\t purge files full-path prefix\n"
+ "\t-D, --dump-prefix\t dump files full-path prefix\n"
+ "\t--super-user\t user allowed to bypass authorization and indexing\n"
+ "\t--super-users-file\t the same but read the subjects from a file\n"
+ "\t--no-index=1\t don't enforce indices for superusers\n"
+ "\t =2\t don't enforce indices at all\n"
+ "\t--strict-locking=1\t lock jobs also on storing events (may be slow)\n"
+ "\t--notif-il-sock\t socket to send notifications\n"
+ ,me);
+}
+
+
+static int decrement_timeout(struct timeval *timeout, struct timeval before, struct timeval after)
+{
+ (*timeout).tv_sec = (*timeout).tv_sec - (after.tv_sec - before.tv_sec);
+ (*timeout).tv_usec = (*timeout).tv_usec - (after.tv_usec - before.tv_usec);
+ while ( (*timeout).tv_usec < 0) {
+ (*timeout).tv_sec--;
+ (*timeout).tv_usec += 1000000;
+ }
+ if ( ((*timeout).tv_sec < 0) || (((*timeout).tv_sec == 0) && ((*timeout).tv_usec == 0)) ) return(1);
+ else return(0);
+}
+
+static int check_timeout(struct timeval *timeout, struct timeval before, struct timeval after)
+{
+ return (timeout->tv_usec <= after.tv_usec - before.tv_usec) ?
+ (timeout->tv_sec <= after.tv_sec - before.tv_sec) :
+ (timeout->tv_sec < after.tv_sec - before.tv_sec);
+}
+
+static void clnt_reject(void *mycred, int conn)
+{
+ int flags = fcntl(conn, F_GETFL, 0);
+
+ if (fcntl(conn, F_SETFL, flags | O_NONBLOCK) < 0)
+ return;
+
+ edg_wll_ssl_reject(mycred, conn);
+ return;
+}
+
+
+#define MSG_BUFSIZ 15
+
+/* send socket sock through socket to_sock */
+static int do_sendmsg(int to_sock, int sock, unsigned long clnt_dispatched,int store) {
+
+ struct msghdr msg = {0};
+ struct cmsghdr *cmsg;
+ int myfds; /* Contains the file descriptors to pass. */
+ char buf[CMSG_SPACE(sizeof myfds)]; /* ancillary data buffer */
+ int *fdptr;
+ struct iovec sendiov;
+ char sendbuf[MSG_BUFSIZ]; /* to store unsigned int + \0 */
+
+
+ snprintf(sendbuf,sizeof(sendbuf),"%c %lu",store?'S':'Q',clnt_dispatched);
+
+ msg.msg_name = NULL;
+ msg.msg_namelen = 0;
+ msg.msg_iov = &sendiov;
+ msg.msg_iovlen = 1;
+ sendiov.iov_base = sendbuf;
+ sendiov.iov_len = sizeof(sendbuf);
+
+ msg.msg_control = buf;
+ msg.msg_controllen = sizeof buf;
+
+ cmsg = CMSG_FIRSTHDR(&msg);
+ cmsg->cmsg_level = SOL_SOCKET;
+ cmsg->cmsg_type = SCM_RIGHTS;
+ cmsg->cmsg_len = CMSG_LEN(sizeof(int));
+ fdptr = (int *)CMSG_DATA(cmsg);
+ *fdptr = sock;
+
+ msg.msg_controllen = cmsg->cmsg_len;
+ /* send fd to server-slave to do rest of communication */
+ if (sendmsg(to_sock, &msg, 0) < 0)
+ return 1;
+
+ return 0;
+}
+
+
+/* receive socket sock through socket from_sock */
+static int do_recvmsg(int from_sock, int *sock, unsigned long *clnt_accepted,int *store) {
+
+ struct msghdr msg = {0};
+ struct cmsghdr *cmsg;
+ int myfds; /* Contains the file descriptors to pass. */
+ char buf[CMSG_SPACE(sizeof(myfds))]; /* ancillary data buffer */
+ struct iovec recviov;
+ char recvbuf[MSG_BUFSIZ],op;
+
+
+ msg.msg_name = NULL;
+ msg.msg_namelen = 0;
+ msg.msg_iov = &recviov;
+ msg.msg_iovlen = 1;
+ recviov.iov_base = recvbuf;
+ recviov.iov_len = sizeof(recvbuf);
+
+ msg.msg_control = buf;
+ msg.msg_controllen = sizeof buf;
+
+ cmsg = CMSG_FIRSTHDR(&msg);
+ cmsg->cmsg_level = SOL_SOCKET;
+ cmsg->cmsg_type = SCM_RIGHTS;
+ cmsg->cmsg_len = CMSG_LEN(sizeof(int));
+ msg.msg_controllen = cmsg->cmsg_len;
+
+ if (recvmsg(from_sock, &msg, 0) < 0)
+ return 1;
+
+ *sock = *((int *)CMSG_DATA(cmsg));
+ sscanf(recvbuf,"%c %lu",&op,clnt_accepted);
+ *store = op == 'S';
+
+ return 0;
+}
+
+
+struct asyn_result {
+ struct hostent *ent;
+ int err;
+};
+
+/* ares callback handler for ares_gethostbyaddr() */
+static void callback_handler(void *arg, int status, struct hostent *h) {
+ struct asyn_result *arp = (struct asyn_result *) arg;
+
+ switch (status) {
+ case ARES_SUCCESS:
+ if (h && h->h_name) {
+ arp->ent->h_name = strdup(h->h_name);
+ if (arp->ent->h_name == NULL) {
+ arp->err = NETDB_INTERNAL;
+ } else {
+ arp->err = NETDB_SUCCESS;
+ }
+ } else {
+ arp->err = NO_DATA;
+ }
+ break;
+ case ARES_EBADNAME:
+ case ARES_ENOTFOUND:
+ arp->err = HOST_NOT_FOUND;
+ break;
+ case ARES_ENOTIMP:
+ arp->err = NO_RECOVERY;
+ break;
+ case ARES_ENOMEM:
+ case ARES_EDESTRUCTION:
+ default:
+ arp->err = NETDB_INTERNAL;
+ break;
+ }
+}
+
+static void free_hostent(struct hostent *h){
+ int i;
+
+ if (h) {
+ if (h->h_name) free(h->h_name);
+ if (h->h_aliases) {
+ for (i=0; h->h_aliases[i]; i++) free(h->h_aliases[i]);
+ free(h->h_aliases);
+ }
+ if (h->h_addr_list) {
+ for (i=0; h->h_addr_list[i]; i++) free(h->h_addr_list[i]);
+ free(h->h_addr_list);
+ }
+ free(h);
+ }
+}
+
+static int asyn_gethostbyaddr(char **name, const char *addr,int len, int type, struct timeval *timeout) {
+ struct asyn_result ar;
+ ares_channel channel;
+ int nfds;
+ fd_set readers, writers;
+ struct timeval tv, *tvp;
+ struct timeval start_time,check_time;
+
+
+/* start timer */
+ gettimeofday(&start_time,0);
+
+/* ares init */
+ if ( ares_init(&channel) != ARES_SUCCESS ) return(NETDB_INTERNAL);
+ ar.ent = (struct hostent *) malloc (sizeof(*ar.ent));
+ memset((void *) ar.ent, 0, sizeof(*ar.ent));
+
+/* query DNS server asynchronously */
+ ares_gethostbyaddr(channel, addr, len, type, callback_handler, (void *) &ar);
+
+/* wait for result */
+ while (1) {
+ FD_ZERO(&readers);
+ FD_ZERO(&writers);
+ nfds = ares_fds(channel, &readers, &writers);
+ if (nfds == 0)
+ break;
+
+ gettimeofday(&check_time,0);
+ if (decrement_timeout(timeout, start_time, check_time)) {
+ ares_destroy(channel);
+ free_hostent(ar.ent);
+ return(TRY_AGAIN);
+ }
+ start_time = check_time;
+
+ tvp = ares_timeout(channel, timeout, &tv);
+
+ switch ( select(nfds, &readers, &writers, NULL, tvp) ) {
+ case -1: if (errno != EINTR) {
+ ares_destroy(channel);
+ free_hostent(ar.ent);
+ return NETDB_INTERNAL;
+ } else
+ continue;
+ case 0:
+ FD_ZERO(&readers);
+ FD_ZERO(&writers);
+ /* fallthrough */
+ default : ares_process(channel, &readers, &writers);
+ }
+
+ }
+
+
+ ares_destroy(channel);
+
+ if (ar.err == NETDB_SUCCESS) {
+ *name = strdup(ar.ent->h_name);
+ free_hostent(ar.ent);
+ }
+ return (ar.err);
+}
+
+static int read_roots(const char *file)
+{
+ FILE *roots = fopen(file,"r");
+ char buf[BUFSIZ];
+ int cnt = 0;
+
+ if (!roots) {
+ perror(file);
+ return 1;
+ }
+
+ while (!feof(roots)) {
+ char *nl;
+ fgets(buf,sizeof buf,roots);
+ nl = strchr(buf,'\n');
+ if (nl) *nl = 0;
+
+ super_users = realloc(super_users, (cnt+1) * sizeof super_users[0]);
+ super_users[cnt] = strdup(buf);
+ super_users[++cnt] = NULL;
+ }
+
+ fclose(roots);
+
+ return 0;
+}
+
+static int amIroot(const char *subj)
+{
+ int i;
+
+ if (!subj) return 0;
+ for (i=0; super_users && super_users[i]; i++)
+ if (strcmp(subj,super_users[i]) == 0) return 1;
+
+ return 0;
+}
+
+static int parse_limits(char *opt, int *j_limit, int *e_limit, int *size_limit)
+{
+ return (sscanf(opt, "%d:%d:%d", j_limit, e_limit, size_limit) == 3);
+}
+
+static unsigned long clnt_dispatched=0, clnt_accepted=0;
+static void *mycred;
+static int server_sock,store_sock;
+
+static int check_mkdir(const char *);
+
+int main(int argc,char *argv[])
+{
+ int fd,i;
+ struct sockaddr_in a;
+ struct sigaction sa;
+ sigset_t sset;
+ char *mysubj = NULL;
+ int opt;
+ char *cert,*key,*port;
+ char *name,pidfile[PATH_MAX] = EDG_BKSERVERD_PIDFILE;
+ int sock_slave[2];
+ FILE *fpid;
+ key_t semkey;
+ time_t cert_mtime = 0,key_mtime = 0;
+ edg_wll_Context ctx;
+
+ name = strrchr(argv[0],'/');
+ if (name) name++; else name = argv[0];
+
+ asprintf(&port,"%d",GLITE_WMSC_JOBID_DEFAULT_PORT);
+ cert = key = cadir = vomsdir = NULL;
+
+/* no magic here: 1 month, 3 and 7 days */
+ purge_timeout[EDG_WLL_PURGE_JOBSTAT_OTHER] = 60*60*24*31;
+ purge_timeout[EDG_WLL_JOB_CLEARED] = 60*60*24*3;
+ purge_timeout[EDG_WLL_JOB_ABORTED] = 60*60*24*7;
+ purge_timeout[EDG_WLL_JOB_CANCELLED] = 60*60*24*7;
+
+/* no magic here: 1 month, 3 and 7 days */
+ purge_timeout[EDG_WLL_PURGE_JOBSTAT_OTHER] = 60*60*24*31;
+ purge_timeout[EDG_WLL_JOB_CLEARED] = 60*60*24*3;
+ purge_timeout[EDG_WLL_JOB_ABORTED] = 60*60*24*7;
+ purge_timeout[EDG_WLL_JOB_CANCELLED] = 60*60*24*7;
+
+/* no magic here: 1 month, 3 and 7 days */
+ purge_timeout[EDG_WLL_PURGE_JOBSTAT_OTHER] = 60*60*24*31;
+ purge_timeout[EDG_WLL_JOB_CLEARED] = 60*60*24*3;
+ purge_timeout[EDG_WLL_JOB_ABORTED] = 60*60*24*7;
+ purge_timeout[EDG_WLL_JOB_CANCELLED] = 60*60*24*7;
+
+ if (geteuid()) snprintf(pidfile,sizeof pidfile,"%s/edg-bkserverd.pid",
+ getenv("HOME"));
+
+ while ((opt = getopt_long(argc,argv,"a:c:k:C:V:p:drm:ns:l:L:N:i:S:D:X:",opts,NULL)) != EOF) switch (opt) {
+ case 'a': fake_host = strdup(optarg); break;
+ case 'c': cert = optarg; break;
+ case 'k': key = optarg; break;
+ case 'C': cadir = optarg; break;
+ case 'V': vomsdir = optarg; break;
+ case 'p': free(port); port = strdup(optarg); break;
+ case 'd': debug = 1; break;
+ case 'r': rgma_export = 1; break;
+ case 'm': dbstring = optarg; break;
+ case 'n': noAuth = 1; break;
+ case 's': slaves = atoi(optarg); break;
+ case 'l': semaphores = atoi(optarg); break;
+ case 'S': purgeStorage = optarg; break;
+ case 'D': dumpStorage = optarg; break;
+ case 'L':
+ if ( !parse_limits(optarg, &hardJobsLimit, &hardEventsLimit, &hardRespSizeLimit) )
+ {
+ usage(name);
+ return 1;
+ }
+ break;
+ case 'N': notif_duration = atoi(optarg) * (60*60); break;
+ case 'X': notif_ilog_socket_path = strdup(optarg); break;
+ case 'i': strcpy(pidfile,optarg); break;
+ case 'R': if (super_users) {
+ fprintf(stderr,"%s: super-users already defined, second occurence ignored\n",
+ argv[0]);
+ break;
+ }
+ super_users = malloc(2 * sizeof super_users[0]);
+ super_users[0] = optarg;
+ super_users[1] = NULL;
+ break;
+ case 'F': if (super_users) {
+ fprintf(stderr,"%s: super-users already defined, second occurence ignored\n",
+ argv[0]);
+ break;
+ }
+ if (read_roots(optarg)) return 1;
+ break;
+ case 'x': noIndex = atoi(optarg);
+ if (noIndex < 0 || noIndex > 2) { usage(name); return 1; }
+ break;
+ case 'P': strict_locking = 1;
+ break;
+ case '?': usage(name); return 1;
+ }
+
+ if (optind < argc) { usage(name); return 1; }
+
+ setlinebuf(stdout);
+ setlinebuf(stderr);
+
+ dprintf(("Master pid %d\n",getpid()));
+ fpid = fopen(pidfile,"r");
+ if (fpid) {
+ int opid = -1;
+ if (fscanf(fpid,"%d",&opid) == 1) {
+ if (!kill(opid,0)) {
+ fprintf(stderr,"%s: another instance running, pid = %d\n",argv[0],opid);
+ return 1;
+ } else if (errno != ESRCH) {
+ perror("kill()"); return 1;
+ }
+ }
+ fclose(fpid);
+ } else if (errno != ENOENT) { perror(pidfile); return 1; }
+
+ fpid = fopen(pidfile,"w");
+ if (!fpid) { perror(pidfile); return 1; }
+ fprintf(fpid,"%d",getpid());
+ fclose(fpid);
+
+ semkey = ftok(pidfile,0);
+
+ if (!debug) for (fd=3; fd<OPEN_MAX; fd++) close(fd);
+
+ if (check_mkdir(dumpStorage)) exit(1);
+ if (check_mkdir(purgeStorage)) exit(1);
+
+ if (semaphores == -1) semaphores = slaves;
+ semset = semget(semkey,0,0);
+ if (semset >= 0) semctl(semset,0,IPC_RMID);
+ semset = semget(semkey,semaphores,IPC_CREAT | 0600);
+ if (semset < 0) { perror("semget()"); return 1; }
+ dprintf(("Using %d semaphores, set id %d\n",semaphores,semset));
+ for (i=0; i<semaphores; i++) {
+ struct sembuf s;
+
+ s.sem_num = i; s.sem_op = 1; s.sem_flg = 0;
+ if (semop(semset,&s,1) == -1) { perror("semop()"); return 1; }
+ }
+
+ if (fake_host) {
+ char *p = strchr(fake_host,':');
+ if (p) {
+ *p = 0;
+ fake_port = atoi(p+1);
+ } else fake_port = atoi(port);
+ }
+ else {
+ char buf[300];
+
+ if (globus_module_activate(GLOBUS_COMMON_MODULE) != GLOBUS_SUCCESS) {
+ dprintf(("[%d]: Unable to initialize Globus common module\n",getpid()));
+ if (!debug) syslog(LOG_CRIT,"Unable to initialize Globus common module\n");
+ }
+
+ globus_libc_gethostname(buf,sizeof buf);
+ buf[sizeof buf - 1] = 0;
+ fake_host = strdup(buf);
+ fake_port = atoi(port);
+ }
+
+ dprintf(("server address: %s:%d\n",fake_host,fake_port));
+
+ server_sock = socket(PF_INET,SOCK_STREAM,0);
+ if (server_sock<0) { perror("socket()"); return 1; }
+
+ a.sin_family = AF_INET;
+ a.sin_port = htons(atoi(port));
+ a.sin_addr.s_addr = INADDR_ANY;
+
+ setsockopt(server_sock, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one));
+ if (bind(server_sock,(struct sockaddr *) &a,sizeof(a))) {
+ char buf[100];
+ snprintf(buf,sizeof(buf),"bind(%d)",atoi(port));
+ perror(buf);
+ return 1;
+ }
+
+ if (listen(server_sock,CON_QUEUE)) { perror("listen()"); return 1; }
+
+ store_sock = socket(PF_INET,SOCK_STREAM,0);
+ if (store_sock<0) { perror("socket()"); return 1; }
+
+ a.sin_family = AF_INET;
+ a.sin_port = htons(atoi(port)+1);
+ a.sin_addr.s_addr = INADDR_ANY;
+
+ setsockopt(store_sock, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one));
+ if (bind(store_sock,(struct sockaddr *) &a,sizeof(a))) {
+ char buf[100];
+ snprintf(buf,sizeof(buf),"bind(%d)",atoi(port)+1);
+ perror(buf);
+ return 1;
+ }
+ if (listen(store_sock,CON_QUEUE)) { perror("listen()"); return 1; }
+
+ if (socketpair(AF_UNIX, SOCK_STREAM, 0, sock_slave)) {
+ perror("socketpair()");
+ return 1;
+ }
+
+ dprintf(("Initializing SSL ...\n"));
+ edg_wlc_SSLInitialization();
+ if (!cert || !key) fprintf(stderr,"%s: key or certificate file not specified - unable to watch them for changes!\n",argv[0]);
+
+ if (cadir) setenv("X509_CERT_DIR",cadir,1);
+ mycred = edg_wll_ssl_init(SSL_VERIFY_PEER,1,cert,key,0,0);
+ edg_wll_ssl_get_my_subject_base(mycred,&mysubj);
+ if (mysubj) {
+ int i;
+ dprintf(("Server identity: %s\n",mysubj));
+
+ for (i=0; super_users && super_users[i]; i++);
+ super_users = realloc(super_users,(i+2) * sizeof *super_users);
+ super_users[i] = mysubj;
+ super_users[i+1] = NULL;
+ }
+ else dprintf(("Running unauthenticated\n"));
+
+ if (noAuth) dprintf(("Promiscuous mode\n"));
+ dprintf(("Listening at %d,%d (accepting protocols: " COMP_PROTO " and compatible) ...\n",atoi(port),atoi(port)+1));
+
+ if (!dbstring) dbstring = getenv("LBDB");
+
+ /* Just check the database and let it be. The slaves do the job. */
+ edg_wll_InitContext(&ctx);
+ wait_for_open(ctx,dbstring);
+
+ if (edg_wll_DBCheckVersion(ctx)) {
+ char *et,*ed;
+ edg_wll_Error(ctx,&et,&ed);
+
+ fprintf(stderr,"%s: open database: %s (%s)\n",argv[0],et,ed);
+ return 1;
+ }
+ edg_wll_Close(ctx);
+ edg_wll_FreeContext(ctx);
+
+ if (!debug) {
+ if (daemon(1,0) == -1) {
+ perror("deamon()");
+ exit(1);
+ }
+
+ fpid = fopen(pidfile,"w");
+ if (!fpid) { perror(pidfile); return 1; }
+ fprintf(fpid,"%d",getpid());
+ fclose(fpid);
+
+ openlog(name,LOG_PID,LOG_DAEMON);
+ } else {
+ setpgid(0, getpid());
+ }
+
+ memset(&sa,0,sizeof(sa)); assert(sa.sa_handler == NULL);
+ sa.sa_handler = catchsig;
+ sigaction(SIGINT,&sa,NULL);
+ sigaction(SIGTERM,&sa,NULL);
+
+ sa.sa_handler = catch_chld;
+ sigaction(SIGCHLD,&sa,NULL);
+
+ sa.sa_handler = SIG_IGN;
+ sigaction(SIGUSR1,&sa,NULL);
+
+ sigemptyset(&sset);
+ sigaddset(&sset,SIGCHLD);
+ sigaddset(&sset,SIGTERM);
+ sigaddset(&sset,SIGINT);
+ sigprocmask(SIG_BLOCK,&sset,NULL);
+
+ for (i=0; i<slaves; i++) slave(mycred,sock_slave[1]);
+
+ while (!die) {
+ fd_set fds;
+ int ret,mx;
+ struct timeval watch_to = { WATCH_TIMEOUT, 0 };
+
+
+ FD_ZERO(&fds);
+ FD_SET(server_sock,&fds);
+ FD_SET(store_sock,&fds);
+ FD_SET(sock_slave[0],&fds);
+
+ switch (edg_wll_ssl_watch_creds(key,cert,&key_mtime,&cert_mtime)) {
+ void *newcred;
+ case 0: break;
+ case 1: newcred = edg_wll_ssl_init(SSL_VERIFY_PEER,1,cert,key,0,0);
+ if (newcred) {
+ dprintf(("reloading credentials"));
+ edg_wll_ssl_free(mycred);
+ mycred = newcred;
+ kill(0,SIGUSR1);
+ }
+ else {
+ dprintf(("reloading credentials failed"));
+ }
+
+ break;
+ case -1: dprintf(("edg_wll_ssl_watch_creds failed\n"));
+ break;
+ }
+
+ mx = server_sock;
+ if (mx < store_sock) mx = store_sock;
+ if (mx < sock_slave[0]) mx = sock_slave[0];
+ sigprocmask(SIG_UNBLOCK,&sset,NULL);
+ ret = select(mx+1,&fds,NULL,NULL,&watch_to);
+ sigprocmask(SIG_BLOCK,&sset,NULL);
+
+// XXX is needed? ctx->p_tmp_timeout.tv_sec = MASTER_TIMEOUT;
+
+ if (ret == -1 && errno != EINTR) {
+ if (debug) perror("select()");
+ else syslog(LOG_CRIT,"select(): %m");
+ return 1;
+ }
+
+ if (child_died) {
+ int pid;
+ while ((pid=waitpid(-1,NULL,WNOHANG))>0) {
+ if (!die) {
+ int newpid = slave(mycred,sock_slave[1]);
+ dprintf(("[master] Servus mortuus [%d] miraculo resurrexit [%d]\n",pid,newpid));
+ }
+ }
+ child_died = 0;
+ continue;
+ }
+
+ if (die) continue;
+
+ if (FD_ISSET(server_sock,&fds) && dispatchit(sock_slave[0],server_sock,0)) continue;
+ if (FD_ISSET(store_sock,&fds) && dispatchit(sock_slave[0],store_sock,1)) continue;
+
+ if (FD_ISSET(sock_slave[0],&fds)) {
+/* slave accepted a request */
+ unsigned long a;
+
+ if ((recv(sock_slave[0],&a,sizeof(a),MSG_WAITALL) == sizeof(a))
+ && a<=clnt_dispatched
+ && (a>clnt_accepted || clnt_accepted>clnt_dispatched)
+ ) clnt_accepted = a;
+ }
+
+ }
+
+ dprintf(("[master] Terminating on signal %d\n",die));
+ if (!debug) syslog(LOG_INFO,"Terminating on signal %d\n",die);
+ kill(0,die);
+ semctl(semset,0,IPC_RMID,0);
+ unlink(pidfile);
+ free(port);
+ edg_wll_ssl_free(mycred);
+ return 0;
+}
+
+static int dispatchit(int sock_slave,int sock,int store)
+{
+ struct sockaddr_in a;
+ int conn;
+ unsigned char *pom;
+ int alen,ret;
+
+ alen=sizeof(a);
+ conn = accept(sock,(struct sockaddr *) &a,&alen);
+
+ if (conn<0) {
+ if (debug) {
+ perror("accept()"); return 1;
+ } else {
+ syslog(LOG_ERR,"accept(): %m");
+ sleep(5);
+ return -1;
+ }
+ }
+
+ alen=sizeof(a);
+ getpeername(conn,(struct sockaddr *)&a,&alen);
+ pom = (char *) &a.sin_addr.s_addr;
+
+ dprintf(("[master] %s connection from %d.%d.%d.%d:%d\n",store?"store":"query",
+ (int) pom[0],(int) pom[1],(int) pom[2],(int) pom[3], ntohs(a.sin_port)));
+
+ ret = 0;
+ if ((clnt_dispatched<clnt_accepted /* wraparound */
+ || clnt_dispatched-clnt_accepted < slaves*SLAVE_OVERLOAD)
+ && !(ret=do_sendmsg(sock_slave,conn,clnt_dispatched++,store))) {
+ /* all done */;
+ dprintf(("[master] Dispatched %lu, last known served %lu\n",clnt_dispatched-1,clnt_accepted));
+ }
+ else {
+ clnt_reject(mycred,conn);
+ dprintf(("[master] Reject due to overload\n"));
+ }
+ close(conn);
+ if (ret) {
+ perror("sendmsg()");
+ if (!debug) syslog(LOG_ERR,"sendmsg(): %m");
+ }
+ return 0;
+}
+
+
+static int slave(void *mycred,int sock)
+{
+ edg_wll_Context ctx;
+ int conn = -1,pid;
+ sigset_t sset;
+ void *mysql;
+ char *server_name = NULL;
+ int conn_cnt = 0;
+ int h_errno;
+ struct sigaction sa;
+ int sockflags;
+ struct timeval client_done,client_start;
+
+ if ((pid = fork())) return pid;
+
+ srandom(getpid()+time(NULL));
+
+ close(server_sock);
+ close(store_sock);
+
+ sigemptyset(&sset);
+ sigaddset(&sset,SIGTERM);
+ sigaddset(&sset,SIGINT);
+ sigaddset(&sset,SIGUSR1);
+
+ memset(&sa,0,sizeof sa);
+ sa.sa_handler = catchsig;
+ sigaction(SIGUSR1,&sa,NULL);
+
+ if ((sockflags = fcntl(sock, F_GETFL, 0)) < 0 ||
+ fcntl(sock, F_SETFL, sockflags | O_NONBLOCK) < 0)
+ {
+ dprintf(("[%d] fcntl(master_sock): %s\n",getpid(),strerror(errno)));
+ if (!debug) syslog(LOG_CRIT,"fcntl(master_sock): %m");
+ exit(1);
+ }
+
+ edg_wll_InitContext(&ctx);
+
+ dprintf(("[%d] Spawned, opening database ...\n",getpid()));
+ if (!dbstring) dbstring = getenv("LBDB");
+
+ wait_for_open(ctx,dbstring);
+
+ mysql = ctx->mysql;
+ if (edg_wll_QueryJobIndices(ctx,&job_index,NULL)) {
+ char *et,*ed;
+ edg_wll_Error(ctx,&et,&ed);
+
+ dprintf(("[%d]: query_job_indices(): %s: %s, no custom indices available\n",getpid(),et,ed));
+ if (!debug) syslog(LOG_ERR,"[%d]: query_job_indices(): %s: %s, no custom indices available\n",getpid(),et,ed);
+ free(et);
+ free(ed);
+ job_index = NULL;
+ }
+ edg_wll_FreeContext(ctx);
+
+ if (job_index) {
+ int i,j, k, maxncol, ncol;
+ ncol = maxncol = 0;
+ for (i=0; job_index[i]; i++) {
+ for (j=0; job_index[i][j].attr; j++) maxncol++;
+ }
+ job_index_cols = calloc(maxncol+1, sizeof(edg_wll_IColumnRec));
+ for (i=0; job_index[i]; i++) {
+ for (j=0; job_index[i][j].attr; j++) {
+ for (k=0; k<ncol && edg_wll_CmpColumn(&job_index_cols[k].qrec, &job_index[i][j]); k++);
+ if (k==ncol) {
+ job_index_cols[ncol].qrec = job_index[i][j];
+ if (job_index[i][j].attr == EDG_WLL_QUERY_ATTR_USERTAG) {
+ job_index_cols[ncol].qrec.attr_id.tag =
+ strdup(job_index[i][j].attr_id.tag);
+ }
+ job_index_cols[ncol].colname =
+ edg_wll_QueryRecToColumn(&job_index_cols[ncol].qrec);
+ ncol++;
+ }
+ }
+ }
+ job_index_cols[ncol].qrec.attr = EDG_WLL_QUERY_ATTR_UNDEF;
+ job_index_cols[ncol].colname = NULL;
+ }
+
+
+ while (!die && (conn_cnt < SLAVE_CONNS_MAX || conn >= 0)) {
+ fd_set fds;
+ int alen,store,max = sock,newconn = -1;
+ int connflags,kick_client = 0;
+ unsigned long seq;
+ X509 *peer;
+ struct timeval dns_to = {DNS_TIMEOUT, 0},
+ check_to = {SLAVE_CHECK_SIGNALS, 0},
+ total_to = { TOTAL_CLNT_TIMEOUT,0 },
+ client_to = { CLNT_TIMEOUT,0 }, now;
+ char *name = NULL;
+ struct sockaddr_in a;
+
+
+ FD_ZERO(&fds);
+ FD_SET(sock,&fds);
+ if (conn >= 0) FD_SET(conn,&fds);
+ if (conn > sock) max = conn;
+
+ sigprocmask(SIG_UNBLOCK,&sset,NULL);
+ switch (select(max+1,&fds,NULL,NULL,&check_to)) {
+ case -1:
+ if (errno != EINTR) {
+ dprintf(("[%d] select(): %s\n",getpid(),strerror(errno)));
+ if (!debug) syslog(LOG_CRIT,"select(): %m");
+ exit(1);
+ }
+ continue;
+ case 0: if (conn < 0) continue;
+ default: break;
+ }
+ sigprocmask(SIG_BLOCK,&sset,NULL);
+
+ gettimeofday(&now,NULL);
+ if (conn >= 0 && (check_timeout(&client_to,client_done,now) ||
+ check_timeout(&total_to,client_start,now)))
+ kick_client = 1;
+
+ if (conn >= 0 && !kick_client && FD_ISSET(conn,&fds)) {
+ /* serve the request */
+
+ dprintf(("[%d] incoming request\n",getpid()));
+
+ ctx->p_tmp_timeout.tv_sec = SLAVE_TIMEOUT;
+ ctx->p_tmp_timeout.tv_usec = 0;
+
+ if (total_to.tv_sec < ctx->p_tmp_timeout.tv_sec)
+ /* XXX: sec = && usec < never happens */
+ {
+ ctx->p_tmp_timeout.tv_sec = total_to.tv_sec;
+ ctx->p_tmp_timeout.tv_usec = total_to.tv_usec;
+ }
+
+ if (store ? edg_wll_StoreProto(ctx) : edg_wll_ServerHTTP(ctx)) {
+ char *errt,*errd;
+ errt = errd = NULL;
+
+ switch (edg_wll_Error(ctx,&errt,&errd)) {
+ case ETIMEDOUT:
+ /* fallthrough */
+ case EDG_WLL_ERROR_SSL:
+ case EPIPE:
+ dprintf(("[%d] %s (%s)\n",getpid(),errt,errd));
+ if (!debug) syslog(LOG_ERR,"%s (%s)",errt,errd);
+ /* fallthrough */
+ case ENOTCONN:
+ edg_wll_ssl_close(ctx->connPool[ctx->connToUse].ssl);
+ ctx->connPool[ctx->connToUse].ssl = NULL; /* XXX: is it necessary ? */
+ edg_wll_FreeContext(ctx);
+ ctx = NULL;
+ close(conn);
+ conn = -1;
+ free(errt); free(errd);
+ dprintf(("[%d] Connection closed\n",getpid()));
+ continue;
+ break;
+ case ENOENT:
+ /* fallthrough */
+ case EINVAL:
+ /* fallthrough */
+ case EPERM:
+ case EEXIST:
+ case EDG_WLL_ERROR_NOINDEX:
+ case E2BIG:
+ dprintf(("[%d] %s (%s)\n",getpid(),errt,errd));
+ if (!debug) syslog(LOG_ERR,"%s (%s)",errt,errd);
+ break; /* no action for non-fatal errors */
+ default:
+ dprintf(("[%d] %s (%s)\n",getpid(),errt,errd));
+ if (!debug) syslog(LOG_CRIT,"%s (%s)",errt,errd);
+ exit(1);
+ }
+ free(errt); free(errd);
+ }
+
+ dprintf(("[%d] request done\n",getpid()));
+ gettimeofday(&client_done,NULL);
+ continue;
+
+ }
+
+
+ if (FD_ISSET(sock,&fds) && conn_cnt < SLAVE_CONNS_MAX) {
+ if (conn >= 0) usleep(100000 + 1000 * (random() % 200));
+ if (do_recvmsg(sock,&newconn,&seq,&store)) switch (errno) {
+ case EINTR: /* XXX: signals are blocked */
+ case EAGAIN: continue;
+ default: dprintf(("[%d] recvmsg(): %s\n",getpid(),strerror(errno)));
+ if (!debug) syslog(LOG_CRIT,"recvmsg(): %m\n");
+ exit(1);
+ }
+ kick_client = 1;
+ }
+
+ if (kick_client && conn >= 0) {
+ if (ctx->connPool[ctx->connToUse].ssl) {
+ struct timeval to = { 0, CLNT_REJECT_TIMEOUT };
+ edg_wll_ssl_close_timeout(ctx->connPool[ctx->connToUse].ssl,&to);
+ ctx->connPool[ctx->connToUse].ssl = NULL;
+ }
+ edg_wll_FreeContext(ctx);
+ close(conn); /* XXX: should not harm */
+ conn = -1;
+ dprintf(("[%d] Idle connection closed\n",getpid()));
+ }
+
+ if (newconn >= 0) {
+ conn = newconn;
+ gettimeofday(&client_start,NULL);
+ client_done.tv_sec = client_start.tv_sec;
+ client_done.tv_usec = client_start.tv_usec;
+
+ switch (send(sock,&seq,sizeof(seq),0)) {
+ case -1:
+ if (debug) perror("send()");
+ else syslog(LOG_CRIT,"send(): %m\n");
+ exit(1);
+ case sizeof(seq): break;
+ default: dprintf(("[%d] send(): incomplete message\n",getpid()));
+ exit(1);
+ }
+
+ dprintf(("[%d] serving %s %lu\n",getpid(),store?"store":"query",seq));
+ conn_cnt++;
+
+ connflags = fcntl(conn, F_GETFL, 0);
+ if (fcntl(conn, F_SETFL, connflags | O_NONBLOCK) < 0) {
+ dprintf(("[%d] can't set O_NONBLOCK mode (%s), closing.\n",
+ getpid(), strerror(errno)));
+ if (!debug) syslog(LOG_ERR,"can't set O_NONBLOCK mode (%s), closing.\n",
+ strerror(errno));
+
+ close(conn);
+ conn = -1;
+ continue;
+ }
+
+ edg_wll_InitContext(&ctx);
+
+ /* Shared structures (pointers) */
+ ctx->mysql = mysql;
+ ctx->job_index_cols = (void*) job_index_cols;
+ ctx->job_index = job_index;
+
+ ctx->notifDuration = notif_duration;
+ ctx->purgeStorage = strdup(purgeStorage);
+ ctx->dumpStorage = strdup(dumpStorage);
+ ctx->hardJobsLimit = hardJobsLimit;
+ ctx->hardEventsLimit = hardEventsLimit;
+ ctx->semset = semset;
+ ctx->semaphores = semaphores;
+ if (noAuth) ctx->noAuth = 1;
+ ctx->rgma_export = rgma_export;
+ memcpy(ctx->purge_timeout,purge_timeout,sizeof ctx->purge_timeout);
+
+ ctx->p_tmp_timeout.tv_sec = SLAVE_TIMEOUT;
+
+ ctx->poolSize = 1;
+ ctx->connPool = calloc(1,sizeof(edg_wll_ConnPool));
+ ctx->connToUse = 0;
+
+ alen = sizeof(a);
+ getpeername(conn,(struct sockaddr *)&a,&alen);
+ ctx->connPool[ctx->connToUse].peerName = strdup(inet_ntoa(a.sin_addr));
+ ctx->connPool[ctx->connToUse].peerPort = ntohs(a.sin_port);
+
+ /* not a critical operation, do not waste all SLAVE_TIMEOUT */
+ switch (h_errno = asyn_gethostbyaddr(&name,(char *) &a.sin_addr.s_addr,sizeof(a.sin_addr.s_addr),
+ AF_INET,&dns_to)) {
+ case NETDB_SUCCESS:
+ if (name) dprintf(("[%d] connection from %s:%d (%s)\n", getpid(),
+ inet_ntoa(a.sin_addr), ntohs(a.sin_port), name));
+ free(ctx->connPool[ctx->connToUse].peerName);
+ ctx->connPool[ctx->connToUse].peerName = name;
+ name = NULL;
+ break;
+ default:
+ if (debug) fprintf(stderr,"gethostbyaddr(%s): %s", inet_ntoa(a.sin_addr), hstrerror(h_errno));
+ /* else syslog(LOG_ERR,"gethostbyaddr(%s): %s", inet_ntoa(a.sin_addr), hstrerror(h_errno)); */
+ dprintf(("[%d] connection from %s:%d\n", getpid(), inet_ntoa(a.sin_addr), ntohs(a.sin_port)));
+ break;
+ }
+
+ gettimeofday(&now,0);
+ if ( decrement_timeout(&ctx->p_tmp_timeout, client_start, now) ) {
+ if (debug) fprintf(stderr,"gethostbyaddr() timeout");
+ else syslog(LOG_ERR,"gethostbyaddr(): timeout");
+ free(name);
+ continue;
+ }
+
+
+ if (fake_host) {
+ ctx->srvName = strdup(fake_host);
+ ctx->srvPort = fake_port;
+ }
+ else {
+ alen = sizeof(a);
+ getsockname(conn,(struct sockaddr *) &a,&alen);
+
+ dns_to.tv_sec = DNS_TIMEOUT;
+ dns_to.tv_usec = 0;
+ switch (h_errno = asyn_gethostbyaddr(&name,(char *) &a.sin_addr.s_addr,sizeof(a.sin_addr.s_addr),
+ AF_INET,&dns_to)) {
+ case NETDB_SUCCESS:
+ ctx->srvName = name;
+ if (server_name != NULL) {
+ if (strcmp(name, server_name)) {
+ if (debug) fprintf(stderr, "different server endpoint names (%s,%s),"
+ " check DNS PTR records\n", name, server_name);
+ else syslog(LOG_ERR,"different server endpoint names (%s,%s),"
+ " check DNS PTR records\n", name, server_name);
+ }
+ } else {
+ server_name = strdup(name);
+ }
+ break;
+ default:
+ if (debug) fprintf(stderr, "gethostbyaddr(%s): %s", inet_ntoa(a.sin_addr), hstrerror(h_errno));
+ else syslog(LOG_ERR,"gethostbyaddr(%s): %s", inet_ntoa(a.sin_addr), hstrerror(h_errno));
+ if (server_name != NULL) {
+ ctx->srvName = strdup(server_name);
+ } else {
+ /* only "GET /jobid" requests refused */
+ }
+ break;
+ }
+ ctx->srvPort = ntohs(a.sin_port);
+ }
+
+ if (!(ctx->connPool[ctx->connToUse].ssl = edg_wll_ssl_accept(mycred,conn,&ctx->p_tmp_timeout))) {
+ dprintf(("[%d] SSL hanshake failed, closing.\n",getpid()));
+ if (!debug) syslog(LOG_ERR,"SSL hanshake failed");
+
+ close(conn);
+ conn = -1;
+ edg_wll_FreeContext(ctx);
+ continue;
+ } else if ((peer = SSL_get_peer_certificate(ctx->connPool[ctx->connToUse].ssl)) != NULL) {
+ X509_NAME *s = X509_get_subject_name(peer);
+
+ proxy_get_base_name(s);
+ free(ctx->peerName);
+ ctx->peerName = X509_NAME_oneline(s,NULL,0);
+ ctx->peerProxyValidity = ASN1_UTCTIME_mktime(X509_get_notAfter(peer));
+ X509_free(peer);
+
+ dprintf(("[%d] client DN: %s\n",getpid(),ctx->peerName));
+ edg_wll_GetVomsGroups(ctx, vomsdir, cadir);
+ if (debug && ctx->vomsGroups.len > 0) {
+ int i;
+
+ dprintf(("[%d] client's VOMS groups:\n",getpid()));
+ for (i = 0; i < ctx->vomsGroups.len; i++)
+ dprintf(("\t%s:%s\n",
+ ctx->vomsGroups.val[i].vo,
+ ctx->vomsGroups.val[i].name));
+ }
+
+ } else dprintf(("[%d] annonymous client\n",getpid()));
+
+ /* used also to reset start_time after edg_wll_ssl_accept! */
+ /* gettimeofday(&start_time,0); */
+
+
+ ctx->noAuth = noAuth || amIroot(ctx->peerName);
+ switch (noIndex) {
+ case 0: ctx->noIndex = 0; break;
+ case 1: ctx->noIndex = amIroot(ctx->peerName); break;
+ case 2: ctx->noIndex = 1; break;
+ }
+ ctx->strict_locking = strict_locking;
+ }
+
+ }
+
+ if (die) {
+ dprintf(("[%d] Terminating on signal %d\n",getpid(),die));
+ if (!debug) syslog(LOG_INFO,"Terminating on signal %d",die);
+ }
+ dprintf(("[%d] Terminating after %d connections\n",getpid(),conn_cnt));
+ if (!debug) syslog(LOG_INFO,"Terminating after %d connections",conn_cnt);
+ exit(0);
+}
+
+static void wait_for_open(edg_wll_Context ctx, const char *dbstring)
+{
+ char *dbfail_string1, *dbfail_string2;
+
+ dbfail_string1 = dbfail_string2 = NULL;
+
+ while (edg_wll_Open(ctx, (char *) dbstring)) {
+ char *errt,*errd;
+
+ if (dbfail_string1) free(dbfail_string1);
+ edg_wll_Error(ctx,&errt,&errd);
+ asprintf(&dbfail_string1,"%s (%s)\n",errt,errd);
+ if (dbfail_string1 != NULL) {
+ if (dbfail_string2 == NULL || strcmp(dbfail_string1,dbfail_string2)) {
+ if (dbfail_string2) free(dbfail_string2);
+ dbfail_string2 = dbfail_string1;
+ dbfail_string1 = NULL;
+ dprintf(("[%d]: %s\nStill trying ...\n",getpid(),dbfail_string2));
+ if (!debug) syslog(LOG_ERR,dbfail_string2);
+ }
+ }
+ sleep(5);
+ }
+
+ if (dbfail_string1) free(dbfail_string1);
+ if (dbfail_string2 != NULL) {
+ free(dbfail_string2);
+ dprintf(("[%d]: DB connection established\n",getpid()));
+ if (!debug) syslog(LOG_INFO,"DB connection established\n");
+ }
+}
+
+static int check_mkdir(const char *dir)
+{
+ struct stat sbuf;
+
+ if (stat(dir,&sbuf)) {
+ if (errno == ENOENT) {
+ if (mkdir(dir, S_IRWXU)) {
+ dprintf(("[%d] %s: %s\n",
+ getpid(),dir,strerror(errno)));
+
+ if (!debug) syslog(LOG_CRIT,"%s: %m",dir);
+ return 1;
+ }
+ }
+ else {
+ dprintf(("[%d] %s: %s\n",getpid(),strerror(errno)));
+ if (!debug) syslog(LOG_CRIT,"%s: %m",dir);
+ return 1;
+ }
+ }
+ else if (S_ISDIR(sbuf.st_mode)) return 0;
+ else {
+ dprintf(("[%d] %s: not a directory\n", getpid(),dir));
+ if (!debug) syslog(LOG_CRIT,"%s: not a directory",dir);
+ return 1;
+ }
+}
--- /dev/null
+#ident "$Header$"
+
+#include <string.h>
+#include <ctype.h>
+#include <errno.h>
+#include <stdlib.h>
+
+#include "glite/lb/consumer.h"
+#include "glite/lb/context-int.h"
+#include "glite/lb/events_parse.h"
+#include "store.h"
+#include "lbs_db.h"
+#include "lock.h"
+
+extern int debug;
+
+/* XXX */
+#define use_db 1
+
+extern int edg_wll_NotifMatch(edg_wll_Context, const edg_wll_JobStat *);
+
+int
+db_store(edg_wll_Context ctx,char *ucs, char *event)
+{
+ edg_wll_Event *ev;
+ int seq;
+ int err;
+ edg_wll_JobStat newstat;
+
+ ev = NULL;
+
+ edg_wll_ResetError(ctx);
+ memset(&newstat,0,sizeof newstat);
+
+ if(edg_wll_ParseEvent(ctx, event, &ev))
+ goto err;
+
+ /* XXX: if event type is user tag, convert the tag name to lowercase!
+ * (not sure whether to convert a value too is reasonable
+ * or keep it 'case sensitive')
+ */
+ if ( ev->any.type == EDG_WLL_EVENT_USERTAG )
+ {
+ int i;
+ for ( i = 0; ev->userTag.name[i] != '\0'; i++ )
+ ev->userTag.name[i] = tolower(ev->userTag.name[i]);
+ }
+
+ if(ev->any.user == NULL)
+ ev->any.user = strdup(ucs);
+
+ if(use_db) {
+ if (ctx->strict_locking && edg_wll_LockJob(ctx,ev->any.jobId)) goto err;
+ if(edg_wll_StoreEvent(ctx, ev,&seq))
+ goto err;
+ }
+
+ if (debug) { fputs(event,stderr); fputc('\n',stderr); }
+
+ if (!ctx->strict_locking && edg_wll_LockJob(ctx,ev->any.jobId)) goto err;
+
+ if ( ev->any.type == EDG_WLL_EVENT_CHANGEACL )
+ err = edg_wll_UpdateACL(ctx, ev->any.jobId,
+ ev->changeACL.user_id, ev->changeACL.user_id_type,
+ ev->changeACL.permission, ev->changeACL.permission_type,
+ ev->changeACL.operation);
+ else
+ err = edg_wll_StepIntState(ctx,ev->any.jobId, ev, seq,&newstat);
+
+ if (edg_wll_UnlockJob(ctx,ev->any.jobId)) goto err;
+ if (err) goto err;
+
+ if (newstat.state) {
+ edg_wll_NotifMatch(ctx,&newstat);
+ edg_wll_FreeStatus(&newstat);
+ }
+
+ edg_wll_FreeEvent(ev);
+ free(ev);
+
+ return(0);
+
+ err:
+ if(ev) {
+ edg_wll_FreeEvent(ev);
+ free(ev);
+ }
+
+ return edg_wll_Error(ctx,NULL,NULL);
+}
+
--- /dev/null
+#ident "$Header$"
+
+#include <time.h>
+#include <stdio.h>
+#include <string.h>
+#include <syslog.h>
+#include <assert.h>
+#include <unistd.h>
+
+#include "glite/lb/trio.h"
+#include "glite/wms/jobid/cjobid.h"
+
+#include "glite/lb/context-int.h"
+#include "glite/lb/events_parse.h"
+#include "glite/lb/ulm_parse.h"
+#include "glite/lb/purge.h"
+#include "glite/lb/purge.h"
+#include "glite/lb/dump.h"
+
+#include "lbs_db.h"
+#include "query.h"
+#include "get_events.h"
+#include "server_state.h"
+#include "purge.h"
+
+static int handle_specials(edg_wll_Context,time_t *);
+
+#define sizofa(a) (sizeof(a)/sizeof((a)[0]))
+
+int edg_wll_DumpEvents(edg_wll_Context ctx,const edg_wll_DumpRequest *req,edg_wll_DumpResult *result)
+{
+ char *from_s, *to_s, *stmt, *time_s;
+ char *tmpfname;
+ time_t start,end;
+ edg_wll_Stmt q = NULL;
+ char *res[10];
+ int event;
+ edg_wll_Event e;
+ int ret,dump = 2; /* TODO: manage dump file */
+ time_t from = req->from,to = req->to;
+
+ from_s = to_s = stmt = NULL;
+ memset(res,0,sizeof res);
+ memset(&e,0,sizeof e);
+
+ time(&start);
+ edg_wll_ResetError(ctx);
+
+ if ( (dump = edg_wll_CreateTmpDumpFile(ctx, &tmpfname)) == -1 )
+ return edg_wll_Error(ctx, NULL, NULL);
+
+ if (handle_specials(ctx,&from) || handle_specials(ctx,&to))
+ {
+ unlink(tmpfname);
+ return edg_wll_Error(ctx,NULL,NULL);
+ }
+
+ from_s = strdup(edg_wll_TimeToDB(from));
+ to_s = strdup(edg_wll_TimeToDB(to));
+
+ trio_asprintf(&stmt,
+ "select event,dg_jobid,code,prog,host,u.cert_subj,time_stamp,usec,level,arrived "
+ "from events e,users u,jobs j "
+ "where u.userid=e.userid "
+ "and j.jobid = e.jobid "
+ "and j.dg_jobid like 'https://%|Ss:%d%%' "
+ "and arrived > '%|Ss' and arrived <= '%|Ss' "
+ "order by arrived",
+ ctx->srvName,ctx->srvPort,
+ from_s,to_s);
+
+ if (edg_wll_ExecStmt(ctx,stmt,&q) < 0) goto clean;
+
+ while ((ret = edg_wll_FetchRow(q,res)) > 0) {
+ assert(ret == sizofa(res));
+ event = atoi(res[0]); free(res[0]); res[0] = NULL;
+
+ if (convert_event_head(ctx,res+1,&e)
+ || edg_wll_get_event_flesh(ctx,event,&e))
+ {
+ char *et,*ed;
+ int i;
+
+ /* Most likely sort of internal inconsistency.
+ * Must not be fatal -- just complain
+ */
+ edg_wll_Error(ctx,&et,&ed);
+ fprintf(stderr,"%s event %d: %s (%s)\n",res[1],event,et,ed);
+ syslog(LOG_WARNING,"%s event %d: %s (%s)",res[1],event,et,ed);
+ free(et); free(ed);
+ for (i=0; i<sizofa(res); i++) free(res[i]);
+ edg_wll_ResetError(ctx);
+ }
+ else {
+ char *event_s = edg_wll_UnparseEvent(ctx,&e);
+ char arr_s[100];
+ int len, written, total;
+
+ strcpy(arr_s, "DG.ARRIVED=");
+ edg_wll_ULMTimevalToDate(e.any.arrived.tv_sec,
+ e.any.arrived.tv_usec,
+ arr_s+strlen("DG.ARRIVED="));
+ len = strlen(arr_s);
+ total = 0;
+ while (total != len) {
+ written = write(dump,arr_s+total,len-total);
+ if (written < 0 && errno != EAGAIN) {
+ edg_wll_SetError(ctx,errno,"writing dump file");
+ free(event_s);
+ goto clean;
+ }
+ total += written;
+ }
+ write(dump, " ", 1);
+ len = strlen(event_s);
+ total = 0;
+ while (total != len) {
+ written = write(dump,event_s+total,len-total);
+ if (written < 0 && errno != EAGAIN) {
+ edg_wll_SetError(ctx,errno,"writing dump file");
+ free(event_s);
+ goto clean;
+ }
+ total += written;
+ }
+ write(dump,"\n",1);
+ free(event_s);
+ }
+ edg_wll_FreeEvent(&e); memset(&e,0,sizeof e);
+ }
+
+ time(&end);
+/* XXX: get rid of apostrophes returned by edg_wll_TimeToDB() */
+ time_s = strdup(edg_wll_TimeToDB(start));
+ time_s[strlen(time_s)-1] = 0;
+ edg_wll_SetServerState(ctx,EDG_WLL_STATE_DUMP_START,time_s+1);
+ free(time_s);
+
+ time_s = strdup(edg_wll_TimeToDB(end));
+ time_s[strlen(time_s)-1] = 0;
+ edg_wll_SetServerState(ctx,EDG_WLL_STATE_DUMP_END,time_s+1);
+ free(time_s);
+
+ result->from = from;
+ result->to = to;
+
+ edg_wll_CreateDumpFileFromTmp(ctx, tmpfname, &(result->server_file));
+ unlink(tmpfname);
+
+clean:
+ edg_wll_FreeEvent(&e);
+ edg_wll_FreeStmt(&q);
+
+ free(stmt);
+ free(from_s);
+ free(to_s);
+ return edg_wll_Error(ctx,NULL,NULL);
+}
+
+static int handle_specials(edg_wll_Context ctx,time_t *t)
+{
+ char *time_s;
+ int ret;
+
+ edg_wll_ResetError(ctx);
+ switch (*t) {
+ case EDG_WLL_DUMP_NOW:
+ time(t);
+ return 0;
+ case EDG_WLL_DUMP_LAST_START:
+ case EDG_WLL_DUMP_LAST_END:
+ switch (ret = edg_wll_GetServerState(ctx,
+ *t == EDG_WLL_DUMP_LAST_START ?
+ EDG_WLL_STATE_DUMP_START:
+ EDG_WLL_STATE_DUMP_END,
+ &time_s))
+ {
+ case ENOENT: *t = 0;
+ edg_wll_ResetError(ctx);
+ break;
+ case 0: *t = edg_wll_DBToTime(time_s);
+ assert(*t >= 0);
+ break;
+ default: break;
+ }
+ break;
+ default: if (*t < 0) return edg_wll_SetError(ctx,EINVAL,"special time limit unrecognized");
+ }
+ return edg_wll_Error(ctx,NULL,NULL);
+}
+
+
--- /dev/null
+#ident "$Header$"
+
+/*
+@@@AUTO
+*/
+@@@LANG: C
+
+/* Helper functions for getting events from the LB database *
+ * XXX: lots of stuff still hadcoded:
+ * there's mapping db.columns <-> union event fields
+ */
+
+#include <assert.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <syslog.h>
+
+#include "get_events.h"
+#include "glite/lb/context-int.h"
+#include "glite/lb/trio.h"
+#include "glite/lb/events_parse.h"
+
+static void edg_wll_set_event_field(edg_wll_Event *,char *,char *);
+static void edg_wll_set_event_field_warn(edg_wll_Event *,char *,char *);
+
+int edg_wll_get_event_flesh(edg_wll_Context ctx,int n,edg_wll_Event *e)
+{
+ char *jobid = edg_wlc_JobIdGetUnique(e->any.jobId),
+ *q = NULL,*nameval[2];
+ edg_wll_Stmt sh;
+ int ret,t;
+ const char *tables[] = { "short_fields","long_fields" };
+
+ edg_wll_ResetError(ctx);
+
+ for (t=0; t<=1; t++) {
+ trio_asprintf(&q,"select name,value from %s "
+ "where jobid = '%|Ss' and event = %d ",
+ tables[t],jobid,n);
+
+ if ((ret=edg_wll_ExecStmt(ctx,q,&sh)) < 0) goto cleanup;
+
+ while ((ret=edg_wll_FetchRow(sh,nameval)) > 0) {
+ edg_wll_set_event_field(e,nameval[0],nameval[1]);
+ free(nameval[0]);
+ /* XXX: nameval[1] freed in edg_wll_set_event_field
+ * if necessary
+ */
+ }
+
+ if (ret<0) goto cleanup;
+ edg_wll_FreeStmt(&sh);
+ free(q); q=NULL;
+ }
+
+ ret=edg_wll_CheckEvent(ctx,e);
+
+cleanup:
+ if (sh) edg_wll_FreeStmt(&sh);
+ free(jobid);
+ free(q);
+
+ if (ret) { edg_wll_FreeEvent(e); memset(e,0,sizeof *e); }
+ return ret;
+}
+
+
+/* print/log warning for database inconsistency */
+
+static void edg_wll_set_event_field_warn(
+ edg_wll_Event *event,
+ char *name,
+ char *value)
+{
+ char *e = edg_wll_EventToString(event->any.type);
+
+ fprintf(stderr, "edg_wll_set_event_field: bad field:"
+ "code=\"%s\" name=\"%s\" value=\"%s\"\n",
+ e, name, value);
+ free(e);
+ /* XXX edg_wll_Log */
+}
+
+/* set event structure field */
+
+static void edg_wll_set_event_field(
+ edg_wll_Event *event,
+ char *name,
+ char *value)
+{
+/* XXX: where's the best place to hande it? */
+ if (!strcasecmp(name,"SRC_INSTANCE")) {
+ event->any.src_instance = value;
+ return;
+ }
+
+/* XXX: handled separately, should go to event_head one day */
+ if (!strcasecmp(name,"SEQCODE")) {
+ event->any.seqcode = value;
+ return;
+ }
+
+@@@{
+ for my $n (getAllFieldsOrdered $event) {
+ my @occ = getFieldOccurence $event $n;
+ next if $#occ == 0 && $occ[0] eq '_common_';
+ selectType $event $occ[0];
+ my $f = selectField $event $n;
+ my $name = getName $f;
+ my $lcname = lc $name;
+ gen qq{
+! if (!strcasecmp(name,"$lcname")) \{
+! switch (event->any.type) \{
+};
+ for (@occ) {
+ next if $_ eq '_common_';
+ selectType $event $_;
+ $f = selectField $event $n;
+ my $fucname = ucfirst $n;
+ my $uctype = uc $_;
+ my $flctype = lcfirst $_;
+ my $frs = $f->{codes} ?
+ "event->$flctype.$name = edg_wll_StringTo$_${fucname}(value);" :
+ fromString $f 'value',"event->$flctype.$name";
+ gen qq{
+! case EDG_WLL_EVENT_$uctype: $frs break;
+};
+ }
+ gen qq{
+! default: edg_wll_set_event_field_warn(event,name,value); break;
+! \} /* switch */
+! free(value);
+! return;
+! \}
+};
+ }
+@@@}
+
+ edg_wll_set_event_field_warn(event,name,value);
+ free(value);
+ return;
+}
+
+
+int compare_events_by_tv(const void *a, const void *b)
+{
+ const edg_wll_Event *e = (edg_wll_Event *)a;
+ const edg_wll_Event *f = (edg_wll_Event *)b;
+
+ if (e->any.timestamp.tv_sec < f->any.timestamp.tv_sec) return -1;
+ if (e->any.timestamp.tv_sec > f->any.timestamp.tv_sec) return 1;
+ if (e->any.timestamp.tv_usec < f->any.timestamp.tv_usec) return -1;
+ if (e->any.timestamp.tv_usec > f->any.timestamp.tv_usec) return 1;
+ return 0;
+}
--- /dev/null
+#ident "$Header$"
+
+/* Internal functions for getting event sets from the LB database */
+#include "lbs_db.h"
+
+#if 0 /* rel 1 */
+char *edg_wll_jobid_to_user( edg_wll_Context, char *);
+void edg_wll_set_event_field_warn( edg_wll_Event *, char *, char *);
+void edg_wll_set_event_field( edg_wll_Event *, char *, char *);
+int edg_wll_get_events_restricted( edg_wll_Context, edg_wlc_JobId, char *, int, int, char *, edg_wll_Event **);
+#define edg_wll_get_events(ctx,job,md5,emin,emax,ret) \
+ edg_wll_get_events_restricted((ctx),(job),(md5),(emin),(emax),NULL,(ret))
+int edg_wll_last_event( edg_wll_Context, char *);
+int compare_events_by_tv(const void *, const void *);
+#endif
+
+int edg_wll_get_event_flesh(edg_wll_Context,int,edg_wll_Event *);
+int edg_wll_QueryEventsServer(edg_wll_Context,int,const edg_wll_QueryRec **,const edg_wll_QueryRec **,edg_wll_Event **);
+
+int edg_wll_QueryJobsServer(edg_wll_Context, const edg_wll_QueryRec **, int, edg_wlc_JobId **, edg_wll_JobStat **);
+
+void edg_wll_SortEvents(edg_wll_Event *);
+int edg_wll_compare_seq(const char *, const char *);
+
--- /dev/null
+/**
+ * il_notification.c
+ * - implementation of IL API calls for notifications
+ *
+ */
+#ident "$Header$"
+
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <sys/types.h>
+#include <fcntl.h>
+#include <string.h>
+#include <errno.h>
+
+#include "glite/lb/context-int.h"
+#include "glite/lb/notifid.h"
+#include "glite/lb/events_parse.h"
+#include "glite/lb/escape.h"
+#include "glite/lb/log_proto.h"
+
+#include "il_notification.h"
+#include "lb_xml_parse.h"
+
+
+
+#define FCNTL_ATTEMPTS 5
+#define FCNTL_TIMEOUT 1
+#define FILE_PREFIX "/tmp/notif_events"
+#define DEFAULT_SOCKET "/tmp/notif_interlogger.sock"
+
+char *notif_ilog_socket_path = DEFAULT_SOCKET;
+
+#define tv_sub(a,b) {\
+ (a).tv_usec -= (b).tv_usec;\
+ (a).tv_sec -= (b).tv_sec;\
+ if ((a).tv_usec < 0) {\
+ (a).tv_sec--;\
+ (a).tv_usec += 1000000;\
+ }\
+}
+
+static
+int
+notif_create_ulm(
+ edg_wll_Context context,
+ edg_wll_NotifId reg_id,
+ const char *host,
+ const uint16_t port,
+ const char *owner,
+ const char *notif_data,
+ char **ulm_data,
+ char **reg_id_s)
+{
+ int ret;
+ edg_wll_Event *event=NULL;
+
+ *ulm_data = NULL;
+ *reg_id_s = NULL;
+
+ event = edg_wll_InitEvent(EDG_WLL_EVENT_NOTIFICATION);
+
+ gettimeofday(&event->any.timestamp,0);
+ if (context->p_host) event->any.host = strdup(context->p_host);
+ event->any.level = context->p_level;
+ event->any.source = context->p_source;
+ if (context->p_instance) event->notification.src_instance = strdup(context->p_instance);
+ event->notification.notifId = reg_id;
+ if (owner) event->notification.owner = strdup(owner);
+ if (host) event->notification.dest_host = strdup(host);
+ event->notification.dest_port = port;
+ if (notif_data) event->notification.jobstat = strdup(notif_data);
+
+ if ((*ulm_data = edg_wll_UnparseNotifEvent(context,event)) == NULL) {
+ edg_wll_SetError(context, ret = ENOMEM, "edg_wll_UnparseNotifEvent()");
+ goto out;
+ }
+
+ if((*reg_id_s = edg_wll_NotifIdGetUnique(reg_id)) == NULL) {
+ edg_wll_SetError(context, ret = ENOMEM, "edg_wll_NotifIdGetUnique()");
+ goto out;
+ }
+
+ ret = 0;
+
+out:
+ if(event) {
+ edg_wll_FreeEvent(event);
+ free(event);
+ }
+ if(ret) edg_wll_UpdateError(context, ret, "notif_create_ulm()");
+ return(ret);
+}
+
+
+static
+int
+notif_save_to_file(edg_wll_Context context,
+ const char *event_file,
+ const char *ulm_data,
+ long *filepos)
+{
+ int ret;
+ FILE *outfile;
+ int filedesc;
+ struct flock filelock;
+ int i, filelock_status=-1;
+
+ for(i=0; i < FCNTL_ATTEMPTS; i++) {
+ /* fopen and properly handle the filelock */
+ if ((outfile = fopen(event_file,"a")) == NULL) {
+ edg_wll_SetError(context, ret = errno, "fopen()");
+ goto out;
+ }
+ if ((filedesc = fileno(outfile)) == -1) {
+ edg_wll_SetError(context, ret = errno, "fileno()");
+ goto out1;
+ }
+ filelock.l_type = F_WRLCK;
+ filelock.l_whence = SEEK_SET;
+ filelock.l_start = 0;
+ filelock.l_len = 0;
+ filelock_status=fcntl(filedesc, F_SETLK, &filelock);
+ if(filelock_status < 0) {
+ switch(errno) {
+ case EAGAIN:
+ case EACCES:
+ case EINTR:
+ /* lock is held by someone else */
+ sleep(FCNTL_TIMEOUT);
+ break;
+ default:
+ /* other error */
+ edg_wll_SetError(context, ret=errno, "fcntl()");
+ goto out1;
+ }
+ } else {
+ /* lock acquired, break out of the loop */
+ break;
+ }
+ }
+ if (fseek(outfile, 0, SEEK_END) == -1) {
+ edg_wll_SetError(context, ret = errno, "fseek()");
+ goto out1;
+ }
+ if ((*filepos=ftell(outfile)) == -1) {
+ edg_wll_SetError(context, ret = errno, "ftell()");
+ goto out1;
+ }
+ /* write, flush and sync */
+ if (fputs(ulm_data, outfile) == EOF) {
+ edg_wll_SetError(context, ret = errno, "fputs()");
+ goto out1;
+ }
+ if (fflush(outfile) == EOF) {
+ edg_wll_SetError(context, ret = errno, "fflush()");
+ goto out1;
+ }
+ if (fsync(filedesc) < 0) { /* synchronize */
+ edg_wll_SetError(context, ret = errno, "fsync()");
+ goto out1;
+ }
+
+ ret = 0;
+out1:
+ /* close and unlock */
+ fclose(outfile);
+out:
+ if(ret) edg_wll_UpdateError(context, ret, "notif_save_to_file()");
+ return(ret);
+}
+
+
+static
+ssize_t
+socket_write_full(edg_wll_Context context,
+ int sock,
+ void *buf,
+ size_t bufsize,
+ struct timeval *timeout,
+ ssize_t *total)
+{
+ int ret = 0;
+ ssize_t len;
+
+ *total = 0;
+ while (bufsize > 0) {
+
+ fd_set fds;
+ struct timeval to,before,after;
+
+ if (timeout) {
+ memcpy(&to, timeout, sizeof(to));
+ gettimeofday(&before, NULL);
+ }
+
+ len = write(sock, buf, bufsize);
+ while (len <= 0) {
+ FD_ZERO(&fds);
+ FD_SET(sock, &fds);
+ if (select(sock+1, &fds, NULL, NULL, timeout ? &to : NULL) < 0) {
+ edg_wll_SetError(context, ret = errno, "select()");
+ goto out;
+ }
+ len = write(sock, buf, bufsize);
+ }
+ if (timeout) {
+ gettimeofday(&after,NULL);
+ tv_sub(after, before);
+ tv_sub(*timeout,after);
+ if (timeout->tv_sec < 0) {
+ timeout->tv_sec = 0;
+ timeout->tv_usec = 0;
+ }
+ }
+
+ if (len < 0) {
+ edg_wll_SetError(context, ret = errno, "write()");
+ goto out;
+ }
+
+ bufsize -= len;
+ buf += len;
+ *total += len;
+ }
+
+ ret = 0;
+out:
+ if(ret) edg_wll_UpdateError(context, ret, "socket_write_full()");
+ return ret;
+}
+
+
+static
+int
+notif_send_socket(edg_wll_Context context,
+ long filepos,
+ const char *ulm_data)
+{
+ int ret;
+ struct sockaddr_un saddr;
+ int msg_sock, flags, count;
+ struct timeval timeout;
+
+ timeout.tv_sec = EDG_WLL_LOG_TIMEOUT_MAX;
+ timeout.tv_usec = 0;
+
+ msg_sock = socket(PF_UNIX, SOCK_STREAM, 0);
+ if(msg_sock < 0) {
+ edg_wll_SetError(context, ret = errno, "socket()");
+ goto out;
+ }
+
+ memset(&saddr, 0, sizeof(saddr));
+ saddr.sun_family = AF_UNIX;
+ strcpy(saddr.sun_path, notif_ilog_socket_path);
+
+ if ((flags = fcntl(msg_sock, F_GETFL, 0)) < 0 ||
+ fcntl(msg_sock, F_SETFL, flags | O_NONBLOCK) < 0) {
+ edg_wll_SetError(context, ret = errno, "fcntl()");
+ goto out1;
+ }
+
+ if(connect(msg_sock, (struct sockaddr *)&saddr, sizeof(saddr)) < 0) {
+ if(errno != EISCONN) {
+ edg_wll_SetError(context, ret = errno, "connect()");
+ goto out1;
+ }
+ }
+
+ if (socket_write_full(context, msg_sock, &filepos, sizeof(filepos), &timeout, &count) < 0) {
+ ret = errno;
+ goto out1;
+ }
+
+ if (socket_write_full(context, msg_sock, (void*)ulm_data, strlen(ulm_data), &timeout, &count) < 0) {
+ ret = errno;
+ goto out1;
+ }
+
+ ret = 0;
+
+out1:
+ close(msg_sock);
+out:
+ if(ret) edg_wll_UpdateError(context, ret, "notif_send_socket()");
+ return(ret);
+}
+
+
+int
+edg_wll_NotifSend(edg_wll_Context context,
+ edg_wll_NotifId reg_id,
+ const char *host,
+ int port,
+ const char *owner,
+ const char *notif_data)
+{
+ int ret;
+ long filepos;
+ char *ulm_data, *reg_id_s, *event_file;
+
+ if((ret=notif_create_ulm(context,
+ reg_id,
+ host,
+ port,
+ owner,
+ notif_data,
+ &ulm_data,
+ ®_id_s))) {
+ goto out;
+ }
+
+ asprintf(&event_file, "%s.%s", FILE_PREFIX, reg_id_s);
+ if(event_file == NULL) {
+ edg_wll_SetError(context, ret=ENOMEM, "asprintf()");
+ goto out;
+ }
+
+ if((ret=notif_save_to_file(context,
+ event_file,
+ ulm_data,
+ &filepos))) {
+ goto out;
+ }
+
+ if((ret=notif_send_socket(context,
+ filepos,
+ ulm_data))) {
+ goto out;
+ }
+ ret = 0;
+
+out:
+ if(ulm_data) free(ulm_data);
+ if(reg_id_s) free(reg_id_s);
+ if(ret) edg_wll_UpdateError(context, ret, "edg_wll_NotifSend()");
+ return(ret);
+}
+
+
+int
+edg_wll_NotifJobStatus(edg_wll_Context context,
+ edg_wll_NotifId reg_id,
+ const char *host,
+ int port,
+ const char *owner,
+ const edg_wll_JobStat notif_job_stat)
+{
+ int ret=0;
+ char *xml_data, *xml_esc_data=NULL;
+
+ if(edg_wll_JobStatusToXML(context, notif_job_stat, &xml_data))
+ goto out;
+
+ if((xml_esc_data = edg_wll_EscapeXML(xml_data)) == NULL) {
+ edg_wll_SetError(context, ret=ENOMEM, "edg_wll_EscapeXML()");
+ goto out;
+ }
+
+ ret=edg_wll_NotifSend(context, reg_id, host, port, owner, xml_esc_data);
+
+out:
+ if(xml_data) free(xml_data);
+ if(xml_esc_data) free(xml_esc_data);
+ if(ret) edg_wll_UpdateError(context, ret, "edg_wll_NotifJobStatus()");
+ return(ret);
+}
+
+
+int
+edg_wll_NotifChangeDestination(edg_wll_Context context,
+ edg_wll_NotifId reg_id,
+ const char *host,
+ int port)
+{
+ return(edg_wll_NotifSend(context, reg_id, host, port, "", ""));
+}
+
+
+int
+edg_wll_NotifCancelRegId(edg_wll_Context context,
+ edg_wll_NotifId reg_id)
+{
+ return(edg_wll_NotifSend(context, reg_id, NULL, 0, "", ""));
+}
+
--- /dev/null
+#ifndef IL_NOTIFICATION_H
+#define IL_NOTIFICATION_H
+
+#ident "$Header$"
+
+/* needed for the edg_wll_NotifId */
+#include "glite/lb/notification.h"
+/* import the edg_wll_JobStat structure */
+#include "glite/lb/jobstat.h"
+
+#ifdef __cplusplus
+#extern "C" {
+#endif
+
+extern char *notif_ilog_socket_path;
+
+/** Send ULM notification string to interlogger.
+ * Stores notification to file according to registration id and send it
+ * to interlogger using local socket.
+ * \param reg_id registration id
+ * \param host,port address to deliver the notification to.
+ * If NULL, it means no further notifications will
+ * follow (the client has unregistered). It always
+ * overrides previous values (ie. changes the
+ * reg_id->client address mapping in interlogger).
+ * \param owner DN of the registration owner, this will be verified
+ * against client's certificate
+ * \param notif_data ULM formatted notification string, may be NULL,
+ * if there is nothing to be sent to client.
+ * \retval 0 OK
+ * \retval EINVAL bad jobId, unknown event code, or the format
+ * string together with the remaining arguments
+ * does not form a valid event
+ * \retval ENOSPC unable to accept the event due to lack of disk
+ * space etc.
+ * \retval ENOMEM failed to allocate memory
+ * \retval EAGAIN non blocking return from the call, the event
+ * did not come through socket, but is backed up
+ * in file
+ */
+int
+edg_wll_NotifSend(edg_wll_Context context,
+ edg_wll_NotifId reg_id,
+ const char *host,
+ int port,
+ const char *owner,
+ const char *notif_data);
+
+
+/** Send job status notification.
+ * Creates ULM notification string and sends it using
+ * edg_wll_NotifSend(). The job status is encoded into XML and escaped
+ * before inclusion into ULM.
+ * \param reg_id registration id
+ * \param host,port address to deliver the notification to.
+ * \param owner DN of the registration owner, this will be verified
+ * against client's certificate
+ * \param notif_job_stat structure describing job status
+ * \see edg_wll_NotifSend()
+ */
+int
+edg_wll_NotifJobStatus(edg_wll_Context context,
+ edg_wll_NotifId reg_id,
+ const char *host,
+ int port,
+ const char *owner,
+ const edg_wll_JobStat notif_job_stat);
+
+
+/** Change address for notification delivery.
+ * Creates ULM string and uses edg_wll_NotifSend() to pass it
+ * to interlogger.
+ * \param reg_id registration id
+ * \param host,port new delivery address
+ * \see edg_wll_NotifSend()
+ */
+int
+edg_wll_NotifChangeDestination(edg_wll_Context context,
+ edg_wll_NotifId reg_id,
+ const char *host,
+ int port);
+
+/** Cancel registration.
+ * Creates ULM string and uses edg_wll_NotifSend() to pass it to
+ * interlogger.
+ * \param reg_id registration id
+ */
+int
+edg_wll_NotifCancelRegId(edg_wll_Context context,
+ edg_wll_NotifId reg_id);
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
--- /dev/null
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+
+#include "glite/lb/context-int.h"
+#include "lbs_db.h"
+#include "index.h"
+
+extern int debug;
+
+#define const_len(c) (sizeof((c))-1)
+
+/* TODO:
+ - better error recovery (skip unrecognised indices etc.)
+ - leaks memory on errors
+*/
+
+int edg_wll_QueryJobIndices(edg_wll_Context ctx,edg_wll_QueryRec *** index_out,char ***keys_out)
+{
+ edg_wll_QueryRec **idx = NULL;
+ edg_wll_Stmt stmt = NULL;
+
+ int i,j,ret;
+
+ static const char *built_in_indices[] = {
+ "PRIMARY",
+ "parent_job",
+ NULL
+ };
+
+/* XXX: "show index from" columns. Matches at least MySQL 4.0.11 */
+
+ char *showcol[12];
+ int Key_name,Seq_in_index,Column_name,Sub_part;
+
+ char **keys = NULL;
+ int *cols = NULL;
+ char **col_names = NULL;
+
+ int nkeys = 0;
+
+ Key_name = Seq_in_index = Column_name = Sub_part = -1;
+
+ if (edg_wll_ExecStmt(ctx,"show index from states",&stmt)<0)
+ return edg_wll_Error(ctx,NULL,NULL);
+
+ while ((ret = edg_wll_FetchRow(stmt,showcol))) {
+ if (ret < 0) return edg_wll_Error(ctx,NULL,NULL);
+ assert(ret <= sizeof showcol/sizeof showcol[0]);
+
+ if (!col_names) {
+ col_names = malloc(ret * sizeof col_names[0]);
+ edg_wll_QueryColumns(stmt,col_names);
+ for (i=0; i<ret; i++)
+ if (!strcasecmp(col_names[i],"Key_name")) Key_name = i;
+ else if (!strcasecmp(col_names[i],"Seq_in_index")) Seq_in_index = i;
+ else if (!strcasecmp(col_names[i],"Column_name")) Column_name = i;
+ else if (!strcasecmp(col_names[i],"Sub_part")) Sub_part = i;
+
+ assert(Key_name >= 0 && Seq_in_index >= 0 &&
+ Column_name >= 0 && Sub_part >= 0);
+
+ }
+
+
+ for (j=0; built_in_indices[j]; j++) {
+ if (strcasecmp(showcol[Key_name],built_in_indices[j]) == 0) {
+ for (i=0; i<ret; i++) free(showcol[i]);
+ goto continue_fetch_index;
+ }
+ }
+
+ for (i=0; i<nkeys && strcasecmp(showcol[Key_name],keys[i]); i++);
+
+ if (i == nkeys) {
+ keys = realloc(keys,(i+2) * sizeof keys[0]);
+ keys[i] = showcol[Key_name];
+ keys[i+1] = NULL;
+ cols = realloc(cols,(i+1) * sizeof cols[0]);
+ cols[i] = 0;
+ idx = realloc(idx,(i+2) * sizeof idx[0]);
+ idx[i] = idx[i+1] = NULL;
+ showcol[Key_name] = NULL;
+ nkeys++;
+ }
+
+ j = atoi(showcol[Seq_in_index])-1;
+ if (cols[i] <= j) {
+ cols[i] = j+1;
+ idx[i] = realloc(idx[i],(j+2)*sizeof idx[i][0]);
+ memset(&idx[i][j+1],0,sizeof idx[i][0]);
+ }
+
+ if (edg_wll_ColumnToQueryRec(showcol[Column_name],&idx[i][j])) {
+ char ed[300];
+ sprintf(ed,"%s(%s): unsupported column",keys[i],showcol[Column_name]);
+ return edg_wll_SetError(ctx,EINVAL,ed);
+ }
+ else idx[i][j].value.i = atoi(showcol[Sub_part]);
+
+ for (i=0; i<ret; i++) free(showcol[i]);
+continue_fetch_index:
+ // just for escaping from nested cycles
+ ; /* prevent compiler to complain */
+ }
+
+ edg_wll_FreeStmt(&stmt);
+ free(cols);
+ free(col_names);
+ if (keys_out) *keys_out = keys; else free(keys);
+ *index_out = idx;
+
+ return edg_wll_ResetError(ctx);
+}
+
+int edg_wll_CmpColumn(const edg_wll_QueryRec *r1,const edg_wll_QueryRec *r2)
+{
+ if (r1->attr != r2->attr) return 1;
+ switch (r1->attr) {
+ case EDG_WLL_QUERY_ATTR_USERTAG:
+ return strcasecmp(r1->attr_id.tag,r2->attr_id.tag);
+ case EDG_WLL_QUERY_ATTR_TIME:
+ return r1->attr_id.state != r2->attr_id.state;
+ default:
+ return 0;
+ }
+}
+
+static struct {
+ const char *name;
+ edg_wll_QueryAttr attr;
+} std_attrs[] =
+{
+@@@{
+ for my $n ($status->getAllFieldsOrdered) {
+ my $f = selectField $status $n;
+ next unless $f->{index};
+ my $u = uc getName $f;
+ gen "\t{ \"$n\", EDG_WLL_QUERY_ATTR_$u },\n";
+ }
+@@@}
+ { NULL, },
+};
+
+int edg_wll_ColumnToQueryRec(const char *col_name,edg_wll_QueryRec *rec)
+{
+ int i;
+
+ memset(rec,0,sizeof *rec);
+ if (strncasecmp(col_name,STD_PREFIX,const_len(STD_PREFIX)) == 0) {
+ for (i=0; std_attrs[i].name
+ && strcasecmp(std_attrs[i].name,col_name+const_len(STD_PREFIX)); i++);
+
+ if (std_attrs[i].name) rec->attr = std_attrs[i].attr;
+ }
+ else if (strncasecmp(col_name,TIME_PREFIX,const_len(TIME_PREFIX)) == 0) {
+ rec->attr_id.state = edg_wll_StringToStat(col_name+const_len(TIME_PREFIX));
+ if (rec->attr_id.state != (edg_wll_JobStatCode) -1) rec->attr = EDG_WLL_QUERY_ATTR_TIME;
+ }
+ else if (strncasecmp(col_name,USR_PREFIX,const_len(USR_PREFIX)) == 0) {
+ rec->attr = EDG_WLL_QUERY_ATTR_USERTAG;
+ rec->attr_id.tag = strdup(col_name+const_len(USR_PREFIX));
+ rec->value.c = NULL;
+ }
+
+ return !rec->attr;
+}
+
+char * edg_wll_QueryRecToColumn(const edg_wll_QueryRec *rec)
+{
+ char col[100] = "";
+
+ if (rec->attr == EDG_WLL_QUERY_ATTR_USERTAG) {
+ strcpy(col,USR_PREFIX);
+ strcat(col,rec->attr_id.tag);
+ }
+ else if (rec->attr == EDG_WLL_QUERY_ATTR_TIME) {
+ char *s = edg_wll_StatToString(rec->attr_id.state);
+
+ if (s) {
+ strcpy(col,TIME_PREFIX);
+ strcat(col,s);
+ free(s);
+ }
+ }
+ else {
+ int i;
+ for (i=0; std_attrs[i].name && std_attrs[i].attr != rec->attr; i++);
+ if (std_attrs[i].name) {
+ strcpy(col,STD_PREFIX);
+ strcat(col,std_attrs[i].name);
+ }
+ }
+
+ return col[0] ? strdup(col) : NULL;
+}
+
+char * edg_wll_QueryRecToColumnExt(const edg_wll_QueryRec *rec)
+{
+ char *intern = edg_wll_QueryRecToColumn(rec),
+ *out;
+
+ if (!intern) return NULL;
+
+ switch (rec->attr) {
+ case EDG_WLL_QUERY_ATTR_USERTAG:
+ out = strdup(intern+const_len(USR_PREFIX));
+ break;
+ case EDG_WLL_QUERY_ATTR_TIME:
+ out = strdup(intern+const_len(TIME_PREFIX));
+ break;
+ default:
+ out = strdup(intern+const_len(STD_PREFIX));
+ break;
+ }
+ free(intern);
+ return out;
+}
+
+void edg_wll_FreeIColumnRec(edg_wll_IColumnRec *icrp)
+{
+ if (icrp->qrec.attr == EDG_WLL_QUERY_ATTR_USERTAG)
+ free(icrp->qrec.attr_id.tag);
+ free(icrp->colname);
+}
+
--- /dev/null
+
+int edg_wll_QueryJobIndices(edg_wll_Context,edg_wll_QueryRec ***,char ***);
+int edg_wll_ColumnToQueryRec(const char *,edg_wll_QueryRec *);
+char * edg_wll_QueryRecToColumn(const edg_wll_QueryRec *);
+char * edg_wll_QueryRecToColumnExt(const edg_wll_QueryRec *);
+
+int edg_wll_ParseIndexConfig(edg_wll_Context,const char *,edg_wll_QueryRec ***);
+int edg_wll_DumpIndexConfig(edg_wll_Context,const char *,edg_wll_QueryRec * const *);
+
+int edg_wll_CmpColumn(const edg_wll_QueryRec *,const edg_wll_QueryRec *);
+
+typedef struct _edg_wll_IColumnRec {
+ edg_wll_QueryRec qrec;
+ char * colname;
+} edg_wll_IColumnRec;
+
+void edg_wll_FreeIColumnRec(edg_wll_IColumnRec *);
+
+int yylex();
+
+extern int lex_int;
+extern char *lex_out;
+extern int lex_line;
+
+#define STD_PREFIX "STD_"
+#define USR_PREFIX "USR_"
+#define TIME_PREFIX "TIME_"
--- /dev/null
+%{
+#ident "$Header$"
+
+#include <string.h>
+
+#include "glite/lb/context-int.h"
+#include "index_parse.h"
+#include "index.h"
+
+char *lex_out;
+int lex_int;
+int lex_line;
+
+int yywrap(void) { return 1; }
+
+#define YY_NO_UNPUT
+
+%}
+
+
+delim [ \t]
+ws {delim}+
+string \"[^\"\n]*\"
+digit [0-9]
+int {digit}+
+
+%%
+{ws} {}
+
+JobIndices return JOB_INDICES;
+type return TYPE;
+name return NAME;
+prefixlen return PREFIX;
+{int} {
+ lex_int = atoi(yytext);
+ return INT;
+ }
+{string} {
+ int len;
+ lex_out = malloc(len = strlen(yytext)-1);
+ strncpy(lex_out,yytext+1,len-1);
+ lex_out[len-1] = 0;
+ return STRING;
+ }
+\n lex_line++;
+. return *yytext;
+
--- /dev/null
+%{
+#ident "$Header$"
+
+
+#include <stdio.h>
+#include <string.h>
+
+#include "glite/lb/context-int.h"
+
+#include "lbs_db.h"
+#include "index.h"
+
+#define yyerror(x) {}
+
+#define YYDEBUG 1
+
+#define ATTR_TYPE_SYSTEM "system"
+#define ATTR_TYPE_USER "user"
+#define ATTR_TYPE_TIME "time"
+
+static edg_wll_Context parse_ctx;
+static const char *parse_fname;
+
+#define bailout(msg) \
+{ \
+ char *buf; \
+ \
+ asprintf(&buf,"%s:%d: %s",parse_fname,lex_line,(msg)); \
+ edg_wll_SetError(parse_ctx,EINVAL,buf); \
+ free(buf); \
+ YYABORT; \
+}
+
+extern FILE *yyin;
+
+edg_wll_QueryRec **indices_out;
+
+%}
+
+%term JOB_INDICES
+%term STRING
+%term INT
+%term TYPE
+%term NAME
+%term PREFIX
+
+%union
+{
+ char *s;
+ int i;
+ edg_wll_QueryRec qr;
+ edg_wll_QueryRec *qrl;
+ edg_wll_QueryRec **qrll;
+ struct elem_attr {
+ int attr;
+ char *val;
+ } attr;
+}
+
+%type <s> string
+%type <i> int
+%type <qr> job_index_elem
+%type <qrl> job_index job_index_elem_list
+%type <qrll> job_index_list job_indices;
+%type <attr> elem_attr opt_elem_attr
+
+%%
+
+config : '[' job_indices soft_semicolon ']' { indices_out = $2; }
+ ;
+
+job_indices : JOB_INDICES '=' '{' job_index_list soft_comma '}' { $$ = $4; }
+ ;
+
+job_index_list : job_index { $$ = calloc(2,sizeof (*$$)); *$$ = $1; }
+ | job_index_list ',' job_index
+{
+ int i;
+ for (i=0; $1[i]; i++);
+ $$ = realloc($1,(i+2) * sizeof *$1);
+ $$[i] = $3;
+ $$[i+1] = NULL;
+}
+ ;
+
+job_index : job_index_elem { $$ = calloc(2,sizeof (*$$)); memcpy($$,&$1,sizeof $1); }
+ | '{' job_index_elem_list '}' { $$ = $2; }
+ ;
+
+job_index_elem_list : job_index_elem { $$ = calloc(2,sizeof (*$$)); memcpy($$,&$1,sizeof $1); }
+ | job_index_elem_list ',' job_index_elem
+{
+ int i;
+ for (i=0; $1[i].attr; i++);
+ $$ = realloc($1,(i+2) * sizeof *$1);
+ memcpy($$+i,&$3,sizeof $3);
+ memset($$+i+1,0,sizeof *$$);
+}
+ ;
+
+job_index_elem : '[' elem_attr ';' elem_attr opt_elem_attr ']'
+{
+ char *name = $2.attr == NAME ? $2.val :
+ $4.attr == NAME ? $4.val :
+ $5.attr == NAME ? $5.val : NULL,
+ *type = $2.attr == TYPE ? $2.val :
+ $4.attr == TYPE ? $4.val :
+ $5.attr == TYPE ? $5.val : NULL;
+ int prefix = $2.attr == PREFIX ? (int) $2.val :
+ $4.attr == PREFIX ? (int) $4.val :
+ $5.attr == PREFIX ? (int) $5.val : 0;
+
+
+ if (!name) bailout("`name' required");
+ if (!type) bailout("`type' required");
+
+ if (strcasecmp(type,ATTR_TYPE_SYSTEM) == 0) {
+ char *name2;
+ asprintf(&name2,STD_PREFIX "%s",name);
+ if (edg_wll_ColumnToQueryRec(name2,&$$)) bailout("unknown attribute");
+ free(name2);
+ free(name);
+ }
+ else if (strcasecmp(type,ATTR_TYPE_USER) == 0) {
+ $$.attr = EDG_WLL_QUERY_ATTR_USERTAG;
+ $$.attr_id.tag = name;
+ }
+ else if (strcasecmp(type,ATTR_TYPE_TIME) == 0) {
+ char *name2;
+ if (prefix) bailout("PREFIXLEN is not valid with time attributes");
+ asprintf(&name2,TIME_PREFIX "%s",name);
+ if (edg_wll_ColumnToQueryRec(name2,&$$)) bailout("unknown attribute");
+ free(name2);
+ free(name);
+ }
+ else bailout("unknown attr type");
+
+ $$.value.i = prefix;
+}
+ ;
+
+elem_attr : TYPE '=' string { $$.attr = TYPE; $$.val = $3; }
+ | NAME '=' string { $$.attr = NAME; $$.val = $3; }
+ | PREFIX '=' int { $$.attr = PREFIX; $$.val = (char *) $3; }
+ ;
+
+opt_elem_attr : { $$.attr = 0; $$.val = NULL; }
+ | ';' elem_attr { $$ = $2; }
+ ;
+
+string : STRING { $$ = lex_out; lex_out = NULL; }
+ ;
+
+int : INT { $$ = lex_int; }
+ ;
+
+soft_semicolon :
+ | ';'
+ ;
+
+soft_comma :
+ | ','
+ ;
+
+
+%%
+
+
+/* XXX: uses static variables -- non thread-safe */
+
+int edg_wll_ParseIndexConfig(edg_wll_Context ctx,const char *fname,edg_wll_QueryRec ***out)
+{
+ yyin = strcmp(fname,"-") ? fopen(fname,"r") : stdin;
+ lex_line = 1;
+
+ if (!yyin) return edg_wll_SetError(ctx,errno,fname);
+
+ parse_ctx = ctx;
+ parse_fname = fname;
+ edg_wll_ResetError(ctx);
+
+ /* yydebug = 1; */
+ if (yyparse() && !edg_wll_Error(ctx,NULL,NULL)) {
+ char buf[100];
+ if (yyin != stdin) fclose(yyin);
+ sprintf(buf,"%s:%d: parse error",fname,lex_line);
+ return edg_wll_SetError(ctx,EINVAL,buf);
+ }
+ if (yyin != stdin) fclose(yyin);
+
+ if (!edg_wll_Error(ctx,NULL,NULL)) *out = indices_out;
+ indices_out = NULL; /* XXX: memory leak on error but who cares? */
+ return edg_wll_Error(ctx,NULL,NULL);
+}
+
+int edg_wll_DumpIndexConfig(edg_wll_Context ctx,const char *fname,edg_wll_QueryRec * const *idx)
+{
+ int haveit = 0;
+
+ FILE *f = strcmp(fname,"-") ? fopen(fname,"w") : stdout;
+
+ if (!f) return edg_wll_SetError(ctx,errno,fname);
+ if (idx && *idx) { haveit = 1; fputs("[\n\tJobIndices = {\n",f); }
+
+ while (idx && *idx) {
+ const edg_wll_QueryRec *i;
+ int multi = (*idx)[1].attr;
+
+ fputs(multi ? "\t\t{\n" : "\t\t",f);
+
+ for (i=*idx; i->attr; i++) {
+ char *cn = edg_wll_QueryRecToColumnExt(i);
+ char prefix[100] = "";
+ char *type;
+
+ switch (i->attr) {
+ case EDG_WLL_QUERY_ATTR_USERTAG: type = ATTR_TYPE_USER; break;
+ case EDG_WLL_QUERY_ATTR_TIME: type = ATTR_TYPE_TIME; break;
+ default: type = ATTR_TYPE_SYSTEM; break;
+ }
+
+ if (i->value.i) sprintf(prefix,"; prefixlen = %d ",i->value.i);
+ if (multi) fputs("\t\t\t",f);
+ fprintf(f,"[ type = \"%s\"; name = \"%s\" %s]",type,cn,prefix);
+ if (multi) fputs(i[1].attr ? ",\n" : "\n",f);
+ free(cn);
+ }
+
+ if (multi) fputs("\t\t}",f);
+ fputs(idx[1] ? ",\n" : "\n",f);
+
+ idx++;
+ }
+
+ if (haveit) {
+ fputs("\t}\n]\n",f);
+ return edg_wll_ResetError(ctx);
+ }
+ else return edg_wll_SetError(ctx,ENOENT,"no indices");
+}
+
+
--- /dev/null
+#ident "$Header$"
+
+#include <inttypes.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <assert.h>
+#include <stdarg.h>
+#include <regex.h>
+#include <syslog.h>
+
+#include "glite/lb/producer.h"
+#include "glite/lb/context-int.h"
+#include "glite/lb/trio.h"
+
+#include "get_events.h"
+#include "store.h"
+#include "lock.h"
+#include "index.h"
+#include "jobstat.h"
+#include "lb_authz.h"
+
+
+extern int debug;
+
+#define DAG_ENABLE 1
+
+#ifndef dprintf
+#define dprintf(x) { if (debug) printf x; }
+#endif
+
+/* TBD: share in whole logging or workload */
+#ifdef __GNUC__
+#define UNUSED_VAR __attribute__((unused))
+#else
+#define UNUSED_VAR
+#endif
+
+#define RET_FAIL 0
+#define RET_OK 1
+#define RET_FATAL RET_FAIL
+#define RET_SOON 2
+#define RET_LATE 3
+#define RET_BADSEQ 4
+#define RET_SUSPECT 5
+#define RET_IGNORE 6
+#define RET_INTERNAL 100
+
+#define rep(a,b) { free(a); a = (b == NULL) ? NULL : strdup(b); }
+#define mov(a,b) { free(a); a = b; b = NULL; }
+
+static void warn (const char* format, ...) UNUSED_VAR ;
+static char *job_owner(edg_wll_Context,char *);
+static char* location_string(const char*, const char*, const char*);
+static int add_stringlist(char ***, const char *) UNUSED_VAR;
+static int add_taglist(edg_wll_TagValue **, const char *, const char *);
+
+
+int edg_wll_intJobStatus(edg_wll_Context, const edg_wlc_JobId, int, intJobStat *, int);
+edg_wll_ErrorCode edg_wll_StoreIntState(edg_wll_Context, intJobStat *, int);
+edg_wll_ErrorCode edg_wll_LoadIntState(edg_wll_Context , edg_wlc_JobId , int, intJobStat **);
+
+int js_enable_store = 1;
+
+/*
+ * Basic manipulations with the internal representation of job state
+ */
+
+static void init_intJobStat(intJobStat *p)
+{
+ memset(p, 0, sizeof(intJobStat));
+ p->pub.jobtype = EDG_WLL_STAT_SIMPLE;
+ p->pub.children_hist = (int*) calloc(1+EDG_WLL_NUMBER_OF_STATCODES, sizeof(int));
+ p->pub.children_hist[0] = EDG_WLL_NUMBER_OF_STATCODES;
+ p->pub.stateEnterTimes = (int*) calloc(1+EDG_WLL_NUMBER_OF_STATCODES, sizeof(int));
+ p->pub.stateEnterTimes[0] = EDG_WLL_NUMBER_OF_STATCODES;
+ /* TBD: generate */
+}
+
+static void destroy_intJobStat_extension(intJobStat *p)
+{
+ free(p->last_seqcode); p->last_seqcode = NULL;
+ free(p->last_cancel_seqcode); p->last_cancel_seqcode = NULL;
+ p->wontresub = 0;
+}
+
+void destroy_intJobStat(intJobStat *p)
+{
+ edg_wll_FreeStatus(&p->pub);
+ destroy_intJobStat_extension(p);
+ memset(p, 0, sizeof(intJobStat));
+}
+
+#if 0
+static int eval_expect_update(intJobStat *, int *, char **);
+#endif
+
+static int processEvent(intJobStat *, edg_wll_Event *, int, int, char **);
+
+static char* matched_substr(char *, regmatch_t) UNUSED_VAR;
+
+static char* matched_substr(char *in, regmatch_t match)
+{
+ int len;
+ char *s;
+
+ len = match.rm_eo - match.rm_so;
+ s = calloc(1, len + 1);
+ if (s != NULL) {
+ strncpy(s, in + (int)match.rm_so, len);
+ }
+
+ return s;
+}
+
+
+int edg_wll_JobStatus(
+ edg_wll_Context ctx,
+ const edg_wlc_JobId job,
+ int flags,
+ edg_wll_JobStat *stat)
+{
+
+/* Local variables */
+ char *string_jobid;
+ char *md5_jobid;
+
+ intJobStat jobstat;
+ intJobStat *ijsp;
+ int intErr = 0;
+ int lockErr;
+ edg_wll_Acl acl = NULL;
+#if DAG_ENABLE
+ char *stmt = NULL;
+#endif
+
+ edg_wll_ResetError(ctx);
+
+ string_jobid = edg_wlc_JobIdUnparse(job);
+ if (string_jobid == NULL || stat == NULL)
+ return edg_wll_SetError(ctx,EINVAL, NULL);
+ md5_jobid = edg_wlc_JobIdGetUnique(job);
+
+ if ( !(jobstat.pub.owner = job_owner(ctx,md5_jobid)) ) {
+ free(md5_jobid);
+ free(string_jobid);
+ return edg_wll_Error(ctx,NULL,NULL);
+ }
+
+ intErr = edg_wll_GetACL(ctx, job, &acl);
+ if (intErr) {
+ free(md5_jobid);
+ free(string_jobid);
+ return edg_wll_Error(ctx,NULL,NULL);
+ }
+
+ /* authorization check */
+ if ( !(ctx->noAuth) &&
+ (!(ctx->peerName) || strcmp(ctx->peerName, jobstat.pub.owner))) {
+ intErr = (acl == NULL) || edg_wll_CheckACL(ctx, acl, EDG_WLL_PERM_READ);
+ if (intErr) {
+ free(string_jobid);
+ free(md5_jobid);
+ free(jobstat.pub.owner); jobstat.pub.owner = NULL;
+ if (acl) {
+ edg_wll_FreeAcl(acl);
+ return edg_wll_Error(ctx, NULL, NULL);
+ } else {
+ return edg_wll_SetError(ctx,EPERM, "not owner, no ACL is set");
+ }
+ }
+ }
+
+ intErr = edg_wll_LoadIntState(ctx, job, -1 /*all events*/, &ijsp);
+ if (!intErr) {
+ *stat = ijsp->pub;
+ destroy_intJobStat_extension(ijsp);
+ free(ijsp);
+
+ } else {
+ lockErr = edg_wll_LockJob(ctx,job);
+ intErr = edg_wll_intJobStatus(ctx, job, flags,&jobstat, js_enable_store && !lockErr);
+ if (!lockErr) {
+ edg_wll_UnlockJob(ctx,job);
+ }
+
+ *stat = jobstat.pub;
+ if (intErr) edg_wll_FreeStatus(&jobstat.pub);
+ destroy_intJobStat_extension(&jobstat);
+ }
+
+ if (intErr) {
+ free(string_jobid);
+ free(md5_jobid);
+ if (acl) edg_wll_FreeAcl(acl);
+ return edg_wll_Error(ctx, NULL, NULL);
+ }
+
+ if (acl) {
+ stat->acl = strdup(acl->string);
+ edg_wll_FreeAcl(acl);
+ }
+
+ if ((flags & EDG_WLL_STAT_CLASSADS) == 0) {
+ char *null = NULL;
+
+ mov(stat->jdl, null);
+ mov(stat->matched_jdl, null);
+ mov(stat->condor_jdl, null);
+ mov(stat->rsl, null);
+ }
+
+#if DAG_ENABLE
+ if (stat->jobtype == EDG_WLL_STAT_DAG) {
+ if (1) {
+ char *out[2];
+ edg_wll_Stmt sh;
+ int num_sub, num_f;
+
+ if (stat->children_hist == NULL) {
+ stat->children_hist = (int*) calloc(1+EDG_WLL_NUMBER_OF_STATCODES, sizeof(int));
+ stat->children_hist[0] = EDG_WLL_NUMBER_OF_STATCODES;
+ }
+ if ((flags & EDG_WLL_STAT_CHILDREN) == 0) {
+ trio_asprintf(&stmt, "SELECT status FROM states "
+ "WHERE parent_job='%|Ss' AND version='%|Ss'",
+ md5_jobid, INTSTAT_VERSION);
+ out[1] = NULL;
+ } else {
+ trio_asprintf(&stmt, "SELECT s.status,j.dg_jobid FROM states s,jobs j "
+ "WHERE s.parent_job='%|Ss' AND s.version='%|Ss' AND s.jobid=j.jobid",
+ md5_jobid, INTSTAT_VERSION);
+ }
+ if (stmt != NULL) {
+ num_sub = edg_wll_ExecStmt(ctx, stmt, &sh);
+ if (num_sub >=0 ) {
+ while ((num_f = edg_wll_FetchRow(sh, out)) == 1
+ || (num_f == 2)) {
+ num_f = atoi(out[0]);
+ if (num_f > EDG_WLL_JOB_UNDEF && num_f < EDG_WLL_NUMBER_OF_STATCODES)
+ stat->children_hist[num_f+1]++;
+ if (out[1] !=NULL) add_stringlist(&stat->children, out[1]);
+ free(out[0]); free(out[1]);
+ }
+ edg_wll_FreeStmt(&sh);
+ }
+ free(stmt);
+ } else goto dag_enomem;
+ }
+ if (flags & EDG_WLL_STAT_CHILDSTAT) {
+ char *stat_str, *s_out;
+ edg_wll_Stmt sh;
+ int num_sub, num_f, i;
+ intJobStat *js;
+
+ trio_asprintf(&stmt, "SELECT int_status FROM states WHERE parent_job='%|Ss'"
+ " AND version='%|Ss'",
+ md5_jobid, INTSTAT_VERSION);
+ if (stmt != NULL) {
+ num_sub = edg_wll_ExecStmt(ctx, stmt, &sh);
+ if (num_sub >=0 ) {
+ i = 0;
+ stat->children_states = calloc(num_sub+1, sizeof(edg_wll_JobStat));
+ if (stat->children_states == NULL) {
+ edg_wll_FreeStmt(&sh);
+ goto dag_enomem;
+ }
+ while ((num_f = edg_wll_FetchRow(sh, &stat_str)) == 1
+ && i < num_sub) {
+ js = dec_intJobStat(stat_str, &s_out);
+ if (s_out != NULL && js != NULL) {
+ stat->children_states[i] = js->pub;
+ destroy_intJobStat_extension(js);
+ free(js);
+ i++;
+ }
+ free(stat_str);
+ }
+ edg_wll_FreeStmt(&sh);
+ }
+ free(stmt);
+ } else goto dag_enomem;
+ }
+ }
+#endif
+ free(string_jobid);
+ free(md5_jobid);
+ return edg_wll_Error(ctx, NULL, NULL);
+
+#if DAG_ENABLE
+dag_enomem:
+ free(string_jobid);
+ free(md5_jobid);
+ edg_wll_FreeStatus(stat);
+ free(stmt);
+ return edg_wll_SetError(ctx, ENOMEM, NULL);
+#endif
+}
+
+int edg_wll_intJobStatus(
+ edg_wll_Context ctx,
+ const edg_wlc_JobId job,
+ int flags,
+ intJobStat *intstat,
+ int update_db)
+{
+
+/* Local variables */
+ char *string_jobid;
+ char *md5_jobid;
+
+ int num_events;
+ edg_wll_Event *events = NULL;
+
+ int i, intErr = 0;
+ int res;
+ int be_strict = 0;
+ char *errstring = NULL;
+
+ edg_wll_QueryRec jqr[2];
+ edg_wll_QueryRec **jqra;
+
+/* Processing */
+ edg_wll_ResetError(ctx);
+ init_intJobStat(intstat);
+
+ string_jobid = edg_wlc_JobIdUnparse(job);
+ if (string_jobid == NULL || intstat == NULL)
+ return edg_wll_SetError(ctx,EINVAL, NULL);
+
+ /* can be already filled by public edg_wll_JobStat() */
+ if (intstat->pub.owner == NULL) {
+ md5_jobid = edg_wlc_JobIdGetUnique(job);
+ if ( !(intstat->pub.owner = job_owner(ctx,md5_jobid)) ) {
+ free(md5_jobid);
+ free(string_jobid);
+ return edg_wll_Error(ctx,NULL,NULL);
+ }
+ free(md5_jobid);
+ }
+
+ jqr[0].attr = EDG_WLL_QUERY_ATTR_JOBID;
+ jqr[0].op = EDG_WLL_QUERY_OP_EQUAL;
+ jqr[0].value.j = job;
+ jqr[1].attr = EDG_WLL_QUERY_ATTR_UNDEF;
+
+ jqra = (edg_wll_QueryRec **) malloc (2 * sizeof(edg_wll_QueryRec **));
+ jqra[0] = jqr;
+ jqra[1] = NULL;
+
+ if (edg_wll_QueryEventsServer(ctx,1, (const edg_wll_QueryRec **)jqra, NULL, &events)) {
+ free(string_jobid);
+ free(jqra);
+ return edg_wll_Error(ctx, NULL, NULL);
+ }
+ free(jqra);
+
+ for (num_events = 0; events[num_events].type != EDG_WLL_EVENT_UNDEF;
+ num_events++);
+
+ if (num_events == 0) {
+ free(string_jobid);
+ return edg_wll_SetError(ctx,ENOENT,NULL);
+ }
+
+ edg_wll_SortEvents(events);
+
+ for (i = 0; i < num_events; i++) {
+ res = processEvent(intstat, &events[i], i, be_strict, &errstring);
+ if (res == RET_FATAL || res == RET_INTERNAL) { /* !strict */
+ intErr = 1; break;
+ }
+ }
+ if (intstat->pub.state == EDG_WLL_JOB_UNDEF) {
+ intstat->pub.state = EDG_WLL_JOB_UNKNOWN;
+ }
+
+ free(string_jobid);
+
+ for (i=0; i < num_events ; i++) edg_wll_FreeEvent(&events[i]);
+ free(events);
+
+
+ if (intErr) {
+ destroy_intJobStat(intstat);
+ return edg_wll_SetError(ctx, EDG_WLL_ERROR_SERVER_RESPONSE, NULL);
+ } else {
+ /* XXX intstat->pub.expectUpdate = eval_expect_update(intstat, &intstat->pub.expectFrom); */
+ intErr = edg_wlc_JobIdDup(job, &intstat->pub.jobId);
+ if (!intErr) {
+ if (update_db) {
+ int tsq = num_events - 1;
+ edg_wll_StoreIntState(ctx, intstat, tsq);
+ /* recheck
+ * intJobStat *reread;
+ * edg_wll_LoadIntState(ctx, job, tsq, &reread);
+ * destroy_intJobStat(reread);
+ */
+ }
+ }
+ return edg_wll_SetError(ctx, intErr, NULL);
+ }
+
+}
+
+static int badEvent(intJobStat *js UNUSED_VAR, edg_wll_Event *e, int ev_seq UNUSED_VAR)
+{
+ char *str;
+
+ str = edg_wll_EventToString(e->any.type);
+ fprintf(stderr, "edg_wll_JobStatus: bad event: type %d (%s)\n",
+ e->any.type, (str == NULL) ? "unknown" : str);
+ free(str);
+ return RET_FATAL;
+}
+
+#define USABLE(res,strict) ((res) == RET_OK || ( (res) == RET_SOON && !strict))
+#define USABLE_DATA(res,strict) ((res) == RET_OK || ( (res) != RET_FATAL && !strict))
+#define LRMS_STATE(state) ((state) == EDG_WLL_JOB_RUNNING || (state) == EDG_WLL_JOB_DONE)
+
+
+static int processEvent(intJobStat *js, edg_wll_Event *e, int ev_seq, int strict, char **errstring)
+{
+
+ edg_wll_JobStatCode old_state = js->pub.state;
+ edg_wll_JobStatCode new_state = EDG_WLL_JOB_UNKNOWN;
+ int res = RET_OK;
+
+ if (old_state == EDG_WLL_JOB_ABORTED ||
+ old_state == EDG_WLL_JOB_CANCELLED ||
+ old_state == EDG_WLL_JOB_CLEARED) {
+ res = RET_LATE;
+ }
+
+ if (js->last_seqcode != NULL &&
+ edg_wll_compare_seq(e->any.seqcode, js->last_seqcode) < 0) {
+ res = RET_LATE;
+ }
+
+ switch (e->any.type) {
+ case EDG_WLL_EVENT_TRANSFER:
+ if (e->transfer.result == EDG_WLL_TRANSFER_OK) {
+ switch (e->transfer.source) {
+ case EDG_WLL_SOURCE_USER_INTERFACE:
+ new_state = EDG_WLL_JOB_WAITING; break;
+ case EDG_WLL_SOURCE_JOB_SUBMISSION:
+ /* if (LRMS_STATE(old_state)) res = RET_LATE; */
+ new_state = EDG_WLL_JOB_READY; break;
+ case EDG_WLL_SOURCE_LOG_MONITOR:
+ if (LRMS_STATE(old_state)) {
+ js->pub.stateEnterTimes[1 + EDG_WLL_JOB_SCHEDULED] =
+ e->any.timestamp.tv_sec;
+ res = RET_LATE;
+ }
+ new_state = EDG_WLL_JOB_SCHEDULED; break;
+ default:
+ goto bad_event; break;
+ }
+ } else if (e->transfer.result == EDG_WLL_TRANSFER_FAIL) {
+ /* transfer failed */
+ switch (e->transfer.source) {
+ case EDG_WLL_SOURCE_USER_INTERFACE:
+ new_state = EDG_WLL_JOB_SUBMITTED; break;
+ case EDG_WLL_SOURCE_JOB_SUBMISSION:
+ if (LRMS_STATE(old_state)) res = RET_LATE;
+ new_state = EDG_WLL_JOB_READY; break;
+ case EDG_WLL_SOURCE_LOG_MONITOR:
+ if (LRMS_STATE(old_state)) res = RET_LATE;
+ new_state = EDG_WLL_JOB_READY; break;
+ default:
+ goto bad_event; break;
+ }
+ } else {
+ /* e->transfer.result == EDG_WLL_TRANSFER_START */
+ res = RET_IGNORE;
+ }
+ if (USABLE(res, strict)) {
+ js->pub.state = new_state;
+ rep(js->pub.reason, e->transfer.reason);
+
+ free(js->pub.location);
+ if (e->transfer.result == EDG_WLL_TRANSFER_OK) {
+ js->pub.location = location_string(
+ edg_wll_SourceToString(e->transfer.destination),
+ e->transfer.dest_host,
+ e->transfer.dest_instance);
+ } else {
+ js->pub.location = location_string(
+ edg_wll_SourceToString(e->transfer.source),
+ e->transfer.host,
+ e->transfer.src_instance);
+ }
+ }
+ if (USABLE_DATA(res, strict)) {
+ switch (e->transfer.source) {
+ case EDG_WLL_SOURCE_USER_INTERFACE:
+ rep(js->pub.jdl, e->transfer.job); break;
+ case EDG_WLL_SOURCE_JOB_SUBMISSION:
+ rep(js->pub.condor_jdl, e->transfer.job); break;
+ case EDG_WLL_SOURCE_LOG_MONITOR:
+ rep(js->pub.rsl, e->transfer.job); break;
+ default:
+ goto bad_event; break;
+
+ }
+ }
+ break;
+ case EDG_WLL_EVENT_ACCEPTED:
+ switch (e->accepted.source) {
+ case EDG_WLL_SOURCE_NETWORK_SERVER:
+ new_state = EDG_WLL_JOB_WAITING; break;
+ case EDG_WLL_SOURCE_LOG_MONITOR:
+ if (LRMS_STATE(old_state)) res = RET_LATE;
+ new_state = EDG_WLL_JOB_READY; break;
+ case EDG_WLL_SOURCE_LRMS:
+ new_state = EDG_WLL_JOB_SCHEDULED; break;
+ default:
+ goto bad_event; break;
+ }
+ if (USABLE(res, strict)) {
+ js->pub.state = new_state;
+ free(js->pub.location);
+ js->pub.location = location_string(
+ edg_wll_SourceToString(e->accepted.source),
+ e->accepted.host,
+ e->accepted.src_instance);
+ }
+ if (USABLE_DATA(res, strict)) {
+ switch (e->accepted.source) {
+ case EDG_WLL_SOURCE_NETWORK_SERVER:
+ break; /* no WM id */
+ case EDG_WLL_SOURCE_LOG_MONITOR:
+ rep(js->pub.condorId, e->accepted.local_jobid); break;
+ case EDG_WLL_SOURCE_LRMS:
+ /* XXX localId */
+ rep(js->pub.globusId, e->accepted.local_jobid); break;
+ default:
+ goto bad_event; break;
+ }
+ }
+ break;
+ case EDG_WLL_EVENT_REFUSED:
+ switch (e->refused.source) {
+ case EDG_WLL_SOURCE_NETWORK_SERVER:
+ new_state = EDG_WLL_JOB_SUBMITTED; break;
+ case EDG_WLL_SOURCE_LOG_MONITOR:
+ new_state = EDG_WLL_JOB_READY; break;
+ case EDG_WLL_SOURCE_LRMS:
+ new_state = EDG_WLL_JOB_READY; break;
+ default:
+ goto bad_event; break;
+ }
+ if (USABLE(res, strict)) {
+ js->pub.state = new_state;
+ rep(js->pub.reason, e->refused.reason);
+
+ free(js->pub.location);
+ js->pub.location = location_string(
+ edg_wll_SourceToString(e->refused.from),
+ e->refused.from_host,
+ e->refused.from_instance);
+ }
+ break;
+ case EDG_WLL_EVENT_ENQUEUED:
+ if (e->enQueued.result == EDG_WLL_ENQUEUED_OK) {
+ switch (e->enQueued.source) {
+ case EDG_WLL_SOURCE_NETWORK_SERVER:
+ new_state = EDG_WLL_JOB_WAITING; break;
+ case EDG_WLL_SOURCE_WORKLOAD_MANAGER:
+ if (LRMS_STATE(old_state)) res = RET_LATE;
+ new_state = EDG_WLL_JOB_READY; break;
+ case EDG_WLL_SOURCE_LOG_MONITOR:
+ new_state = EDG_WLL_JOB_WAITING; break;
+ default:
+ goto bad_event; break;
+ }
+ } else if (e->enQueued.result == EDG_WLL_ENQUEUED_FAIL) {
+ switch (e->enQueued.source) {
+ case EDG_WLL_SOURCE_NETWORK_SERVER:
+ new_state = EDG_WLL_JOB_WAITING; break;
+ case EDG_WLL_SOURCE_WORKLOAD_MANAGER:
+ new_state = EDG_WLL_JOB_WAITING; break;
+ case EDG_WLL_SOURCE_LOG_MONITOR:
+ new_state = old_state; break;
+ default:
+ goto bad_event; break;
+ }
+ } else {
+ /* e->enQueued.result == EDG_WLL_ENQUEUED_START */
+ res = RET_IGNORE;
+ }
+ if (USABLE(res, strict)) {
+ js->pub.state = new_state;
+ rep(js->pub.reason, e->enQueued.reason);
+
+ free(js->pub.location);
+ if (e->transfer.result == EDG_WLL_ENQUEUED_OK) {
+ js->pub.location = location_string(
+ e->enQueued.queue,
+ e->enQueued.host,
+ e->enQueued.src_instance);
+ if (e->enQueued.source == EDG_WLL_SOURCE_LOG_MONITOR)
+ js->pub.resubmitted = 1;
+ } else {
+ js->pub.location = location_string(
+ edg_wll_SourceToString(e->enQueued.source),
+ e->enQueued.host,
+ e->enQueued.src_instance);
+ }
+ }
+ if (USABLE_DATA(res, strict)) {
+ switch (e->enQueued.source) {
+ case EDG_WLL_SOURCE_NETWORK_SERVER:
+ rep(js->pub.jdl, e->enQueued.job); break;
+ case EDG_WLL_SOURCE_WORKLOAD_MANAGER:
+ rep(js->pub.matched_jdl, e->enQueued.job); break;
+ case EDG_WLL_SOURCE_LOG_MONITOR:
+ /* no interim JDL here */
+ break;
+ default:
+ goto bad_event; break;
+ }
+ }
+ break;
+ case EDG_WLL_EVENT_DEQUEUED:
+ switch (e->deQueued.source) {
+ case EDG_WLL_SOURCE_WORKLOAD_MANAGER:
+ new_state = EDG_WLL_JOB_WAITING; break;
+ case EDG_WLL_SOURCE_JOB_SUBMISSION:
+ if (LRMS_STATE(old_state)) res = RET_LATE;
+ new_state = EDG_WLL_JOB_READY; break;
+ default:
+ goto bad_event; break;
+ }
+ if (USABLE(res, strict)) {
+ js->pub.state = new_state;
+ free(js->pub.location);
+ js->pub.location = location_string(
+ edg_wll_SourceToString(e->deQueued.source),
+ e->deQueued.host,
+ e->deQueued.src_instance);
+ }
+ if (USABLE_DATA(res, strict)) {
+ /* no WM/JSS local jobid */
+ }
+ break;
+ case EDG_WLL_EVENT_HELPERCALL:
+ if (USABLE(res, strict)) {
+ js->pub.state = EDG_WLL_JOB_WAITING;
+ free(js->pub.location);
+ js->pub.location = location_string(
+ e->helperCall.helper_name,
+ e->helperCall.host,
+ e->helperCall.src_instance);
+ /* roles and params used only for debugging */
+ }
+ break;
+ case EDG_WLL_EVENT_HELPERRETURN:
+ if (USABLE(res, strict)) {
+ js->pub.state = EDG_WLL_JOB_WAITING;
+ free(js->pub.location);
+ js->pub.location = location_string(
+ edg_wll_SourceToString(EDG_WLL_SOURCE_WORKLOAD_MANAGER),
+ e->helperReturn.host,
+ e->helperReturn.src_instance);
+ /* roles and retvals used only for debugging */
+ }
+ break;
+ case EDG_WLL_EVENT_RUNNING:
+ if (USABLE(res, strict)) {
+ js->pub.state = EDG_WLL_JOB_RUNNING;
+ free(js->pub.location);
+ js->pub.location = location_string(
+ edg_wll_SourceToString(EDG_WLL_SOURCE_LRMS),
+ "worknode",
+ e->running.node);
+ }
+ if (USABLE_DATA(res, strict)) {
+ rep(js->pub.ce_node, e->running.node);
+ }
+ break;
+ case EDG_WLL_EVENT_RESUBMISSION:
+ if (USABLE(res, strict)) {
+ if (e->resubmission.result == EDG_WLL_RESUBMISSION_WONTRESUB) {
+ rep(js->pub.reason, e->resubmission.reason);
+ }
+ }
+ if (USABLE_DATA(res, strict)) {
+ if (e->resubmission.result == EDG_WLL_RESUBMISSION_WONTRESUB) {
+ js->wontresub = 1;
+ }
+ }
+ break;
+ case EDG_WLL_EVENT_DONE:
+ if (e->any.source == EDG_WLL_SOURCE_LRMS) {
+ /* Done from JobWrapper is not sufficient for transition
+ * to DONE state according its current definition */
+ break;
+ }
+ if (USABLE(res, strict)) {
+ js->pub.state = EDG_WLL_JOB_DONE;
+ rep(js->pub.reason, e->done.reason);
+ switch (e->done.status_code) {
+ case EDG_WLL_DONE_CANCELLED:
+ js->pub.state = EDG_WLL_JOB_CANCELLED;
+ case EDG_WLL_DONE_OK:
+ rep(js->pub.location, "none"); break;
+ default:
+ free(js->pub.location);
+ js->pub.location = location_string(
+ edg_wll_SourceToString(e->done.source),
+ e->done.host,
+ e->done.src_instance);
+ }
+ }
+ if (USABLE_DATA(res, strict)) {
+ switch (e->done.status_code) {
+ case EDG_WLL_DONE_OK:
+ js->pub.exit_code = e->done.exit_code;
+ js->pub.done_code = EDG_WLL_STAT_OK; break;
+ case EDG_WLL_DONE_CANCELLED:
+ js->pub.exit_code = 0;
+ js->pub.done_code = EDG_WLL_STAT_CANCELLED; break;
+ case EDG_WLL_DONE_FAILED:
+ js->pub.exit_code = 0;
+ js->pub.done_code = EDG_WLL_STAT_FAILED; break;
+ default:
+ goto bad_event; break;
+ }
+ }
+ break;
+ case EDG_WLL_EVENT_CANCEL:
+ if (js->last_cancel_seqcode != NULL &&
+ edg_wll_compare_seq(e->any.seqcode, js->last_cancel_seqcode) < 0) {
+ res = RET_LATE;
+ }
+ if (USABLE(res, strict)) {
+ switch (e->cancel.status_code) {
+ case EDG_WLL_CANCEL_REQ:
+ js->pub.cancelling = 1; break;
+ case EDG_WLL_CANCEL_DONE:
+ js->pub.state = EDG_WLL_JOB_CANCELLED;
+ rep(js->pub.reason, e->cancel.reason);
+ rep(js->last_seqcode, e->any.seqcode);
+ rep(js->pub.location, "none");
+ /* fall though */
+ case EDG_WLL_CANCEL_ABORT:
+ js->pub.cancelling = 0; break;
+ default:
+ /* do nothing */
+ break;
+
+ }
+ }
+ if (USABLE_DATA(res, strict)) {
+ rep(js->pub.cancelReason, e->cancel.reason);
+ }
+ break;
+ case EDG_WLL_EVENT_ABORT:
+ if (USABLE(res, strict)) {
+ js->pub.state = EDG_WLL_JOB_ABORTED;
+ rep(js->pub.reason, e->abort.reason);
+ rep(js->pub.location, "none");
+ }
+ break;
+
+ case EDG_WLL_EVENT_CLEAR:
+ if (USABLE(res, strict)) {
+ js->pub.state = EDG_WLL_JOB_CLEARED;
+ rep(js->pub.location, "none");
+ switch (e->clear.reason) {
+ case EDG_WLL_CLEAR_USER:
+ rep(js->pub.reason, "user retrieved output sandbox");
+ break;
+ case EDG_WLL_CLEAR_TIMEOUT:
+ rep(js->pub.reason, "timed out, resource purge forced");
+ break;
+ case EDG_WLL_CLEAR_NOOUTPUT:
+ rep(js->pub.reason, "no output was generated");
+ break;
+ default:
+ goto bad_event; break;
+
+ }
+ }
+ break;
+ case EDG_WLL_EVENT_PURGE:
+ /* ignore, meta-information only */
+ break;
+ case EDG_WLL_EVENT_MATCH:
+ if (USABLE(res, strict)) {
+ js->pub.state = EDG_WLL_JOB_WAITING;
+ js->pub.location = location_string(
+ edg_wll_SourceToString(EDG_WLL_SOURCE_WORKLOAD_MANAGER),
+ e->match.host,
+ e->match.src_instance);
+ }
+ if (USABLE_DATA(res, strict)) {
+ rep(js->pub.destination, e->match.dest_id);
+ }
+ break;
+ case EDG_WLL_EVENT_PENDING:
+ if (USABLE(res, strict)) {
+ js->pub.state = EDG_WLL_JOB_WAITING;
+ rep(js->pub.reason, e->pending.reason);
+ js->pub.location = location_string(
+ edg_wll_SourceToString(EDG_WLL_SOURCE_WORKLOAD_MANAGER),
+ e->match.host,
+ e->match.src_instance);
+ }
+ break;
+ case EDG_WLL_EVENT_REGJOB:
+ if (USABLE(res, strict)) {
+ js->pub.state = EDG_WLL_JOB_SUBMITTED;
+ }
+ if (USABLE_DATA(res, strict)) {
+ rep(js->pub.jdl, e->regJob.jdl);
+ edg_wlc_JobIdFree(js->pub.parent_job);
+ edg_wlc_JobIdDup(e->regJob.parent,
+ &js->pub.parent_job);
+ rep(js->pub.network_server, e->regJob.ns);
+ js->pub.children_num = e->regJob.nsubjobs;
+ if (e->regJob.jobtype == EDG_WLL_REGJOB_DAG
+ || e->regJob.jobtype == EDG_WLL_REGJOB_PARTITIONED) {
+ js->pub.jobtype = EDG_WLL_STAT_DAG;
+ }
+ rep(js->pub.seed, e->regJob.seed);
+ }
+ break;
+ case EDG_WLL_EVENT_USERTAG:
+ if (USABLE_DATA(res, strict)) {
+ if (e->userTag.name != NULL && e->userTag.value != NULL) {
+ add_taglist(&js->pub.user_tags,
+ e->userTag.name, e->userTag.value);
+ } else {
+ goto bad_event;
+ }
+ }
+ break;
+ case EDG_WLL_EVENT_LISTENER:
+ /* ignore, listener port is not part of job status */
+ break;
+ case EDG_WLL_EVENT_CURDESCR:
+ case EDG_WLL_EVENT_CHKPT:
+ case EDG_WLL_EVENT_CHANGEACL:
+ /* ignore, only for event log */
+ break;
+
+ default:
+ goto bad_event;
+ break;
+ }
+
+ if (USABLE(res,strict)) {
+ js->pub.lastUpdateTime = e->any.timestamp;
+ if (old_state != js->pub.state) {
+ js->pub.stateEnterTime = js->pub.lastUpdateTime;
+ js->pub.stateEnterTimes[1 + js->pub.state]
+ = (int)js->pub.lastUpdateTime.tv_sec;
+ }
+ }
+
+ if (USABLE_DATA(res,strict)) {
+ if (e->any.source == EDG_WLL_SOURCE_NETWORK_SERVER &&
+ js->pub.network_server == NULL) {
+ char *inst;
+ inst = e->any.src_instance;
+ asprintf(&js->pub.network_server, "%s%s%s",
+ e->any.host,
+ inst != NULL ? ":" : " ",
+ inst != NULL ? inst : "");
+ }
+ }
+
+ if (e->any.type == EDG_WLL_EVENT_CANCEL) {
+ rep(js->last_cancel_seqcode, e->any.seqcode);
+ } else {
+ rep(js->last_seqcode, e->any.seqcode);
+ }
+
+ return res;
+
+bad_event:
+ badEvent(js,e,ev_seq);
+ return RET_SUSPECT;
+}
+
+/*
+ * Helper for warning printouts
+ */
+
+static void warn(const char* format, ...)
+{
+ va_list l;
+ va_start(l, format);
+
+ /*
+ fprintf(stderr, "Warning: ");
+ vfprintf(stderr, format, l);
+ fputc('\n', stderr);
+ */
+
+ va_end(l);
+}
+
+static char *job_owner(edg_wll_Context ctx,char *md5_jobid)
+{
+ char *stmt = NULL,*out = NULL;
+ edg_wll_Stmt sh;
+ int f = -1;
+
+ edg_wll_ResetError(ctx);
+ trio_asprintf(&stmt,"select cert_subj from users,jobs "
+ "where users.userid = jobs.userid "
+ "and jobs.jobid = '%|Ss'",md5_jobid);
+
+ if (stmt==NULL) {
+ edg_wll_SetError(ctx,ENOMEM, NULL);
+ return NULL;
+ }
+ if (edg_wll_ExecStmt(ctx,stmt,&sh) >= 0) {
+ f=edg_wll_FetchRow(sh,&out);
+ if (f == 0) {
+ if (out) free(out);
+ out = NULL;
+ edg_wll_SetError(ctx,ENOENT,md5_jobid);
+ }
+ }
+ edg_wll_FreeStmt(&sh);
+ free(stmt);
+
+ return out;
+}
+
+
+#if 0
+/* XXX went_through went out */
+static int eval_expect_update(intJobStat *js, int* went_through, char **expect_from)
+{
+ int em = 0;
+ int ft = 0; /* fall through following tests */
+
+ if (ft || (went_through[ EDG_WLL_JOB_OUTPUTREADY ] && !js->done_failed)) ft = 1;
+ if (ft || (went_through[ EDG_WLL_JOB_DONE ] && !js->done_failed)) ft = 1;
+ if (ft || went_through[ EDG_WLL_JOB_CHECKPOINTED ]) ft = 1;
+ if (ft || went_through[ EDG_WLL_JOB_RUNNING ]) {
+ if (js->pub.node == NULL) em |= EXPECT_MASK_JOBMGR;
+ ft = 1;
+ }
+ if (ft || went_through[ EDG_WLL_JOB_SCHEDULED ]) {
+ if (js->pub.jssId == NULL) em |= EXPECT_MASK_JSS;
+ if (js->pub.rsl == NULL) em |= EXPECT_MASK_JSS;
+ if (js->pub.globusId == NULL) em |= EXPECT_MASK_JOBMGR;
+ if (js->pub.localId == NULL) em |= EXPECT_MASK_JOBMGR;
+ if (js->pub.jss_jdl == NULL) em |= EXPECT_MASK_RB;
+ ft = 1;
+ }
+ if (ft || went_through[ EDG_WLL_JOB_READY ]) {
+ if (js->pub.destination == NULL) em |= EXPECT_MASK_RB;
+ ft = 1;
+ }
+ if (ft || went_through[ EDG_WLL_JOB_SUBMITTED ]) {
+ if (js->pub.jdl == NULL) em |= EXPECT_MASK_UI;
+ ft = 1;
+ }
+
+ if (em == 0)
+ *expect_from = NULL;
+ else {
+ asprintf(expect_from, "%s%s%s%s%s%s%s",
+ (em & EXPECT_MASK_UI ) ? EDG_WLL_SOURCE_UI : "",
+ (em & EXPECT_MASK_UI ) ? " " : "",
+ (em & EXPECT_MASK_RB ) ? EDG_WLL_SOURCE_RB : "",
+ (em & EXPECT_MASK_RB ) ? " " : "",
+ (em & EXPECT_MASK_JSS ) ? EDG_WLL_SOURCE_JSS : "",
+ (em & EXPECT_MASK_JSS ) ? " " : "",
+ (em & EXPECT_MASK_JOBMGR ) ? EDG_WLL_SOURCE_JOBMGR : ""
+ );
+ }
+
+ return (em == 0) ? 0 : 1;
+}
+#endif
+
+static char* location_string(const char *source, const char *host, const char *instance)
+{
+ char *ret;
+ asprintf(&ret, "%s/%s/%s", source, host, instance);
+ return ret;
+}
+
+static int add_stringlist(char ***lptr, const char *new_item)
+{
+ char **itptr;
+ int i;
+
+ if (*lptr == NULL) {
+ itptr = (char **) malloc(2*sizeof(char *));
+ itptr[0] = strdup(new_item);
+ itptr[1] = NULL;
+ *lptr = itptr;
+ return 1;
+ } else {
+ for (i = 0, itptr = *lptr; itptr[i] != NULL; i++);
+ itptr = (char **) realloc(*lptr, (i+2)*sizeof(char *));
+ if (itptr != NULL) {
+ itptr[i] = strdup(new_item);
+ itptr[i+1] = NULL;
+ *lptr = itptr;
+ return 1;
+ } else {
+ return 0;
+ }
+ }
+}
+
+static int add_taglist(edg_wll_TagValue **lptr, const char *new_item, const char *new_item2)
+{
+ edg_wll_TagValue *itptr;
+ int i;
+
+ if (*lptr == NULL) {
+ itptr = (edg_wll_TagValue *) calloc(2,sizeof(edg_wll_TagValue));
+ itptr[0].tag = strdup(new_item);
+ itptr[0].value = strdup(new_item2);
+ *lptr = itptr;
+ return 1;
+ } else {
+ for (i = 0, itptr = *lptr; itptr[i].tag != NULL; i++)
+ if ( !strcasecmp(itptr[i].tag, new_item) )
+ {
+ free(itptr[i].value);
+ itptr[i].value = strdup(new_item2);
+ return 1;
+ }
+ itptr = (edg_wll_TagValue *) realloc(*lptr, (i+2)*sizeof(edg_wll_TagValue));
+ if (itptr != NULL) {
+ itptr[i].tag = strdup(new_item);
+ itptr[i].value = strdup(new_item2);
+ itptr[i+1].tag = NULL;
+ itptr[i+1].value = NULL;
+ *lptr = itptr;
+ return 1;
+ } else {
+ return 0;
+ }
+ }
+}
+
+/* XXX more thorough malloc, calloc, and asprintf failure handling */
+/* XXX indexes in {short,long}_fields */
+/* XXX strict mode */
+/* XXX caching */
+
+/*
+ * Store current job state to states and status_tags DB tables.
+ * Should be called with the job locked.
+ */
+
+edg_wll_ErrorCode edg_wll_StoreIntState(edg_wll_Context ctx,
+ intJobStat *stat,
+ int seq)
+{
+ char *jobid_md5, *stat_enc, *parent_md5 = NULL;
+ char *stmt;
+ edg_wll_TagValue *tagp;
+ int update;
+ int dbret;
+ char *icnames, *icvalues;
+
+ update = (seq > 0);
+ jobid_md5 = edg_wlc_JobIdGetUnique(stat->pub.jobId);
+ stat_enc = enc_intJobStat(strdup(""), stat);
+
+ tagp = stat->pub.user_tags;
+ if (tagp) {
+ while ((*tagp).tag != NULL) {
+ trio_asprintf(&stmt, "insert into status_tags"
+ "(jobid,seq,name,value) values "
+ "('%|Ss',%d,'%|Ss','%|Ss')",
+ jobid_md5, seq, (*tagp).tag, (*tagp).value);
+ if (edg_wll_ExecStmt(ctx,stmt,NULL) < 0) {
+ if (EEXIST == edg_wll_Error(ctx, NULL, NULL)) {
+ /* XXX: this should not happen */
+ edg_wll_ResetError(ctx);
+ tagp++;
+ continue;
+ }
+ else
+ goto cleanup;
+ }
+ tagp++;
+ }
+ }
+
+ parent_md5 = edg_wlc_JobIdGetUnique(stat->pub.parent_job);
+ if (parent_md5 == NULL) parent_md5 = strdup("*no parent job*");
+
+
+ edg_wll_IColumnsSQLPart(ctx, ctx->job_index_cols, stat, 0, NULL, &icvalues);
+
+ trio_asprintf(&stmt,
+ "update states set "
+ "status=%d,seq=%d,int_status='%|Ss',version='%|Ss'"
+ ",parent_job='%|Ss'%s "
+ "where jobid='%|Ss'",
+ stat->pub.state, seq, stat_enc, INTSTAT_VERSION,
+ parent_md5, icvalues,
+ jobid_md5);
+ free(icvalues);
+
+ if ((dbret = edg_wll_ExecStmt(ctx,stmt,NULL)) < 0) goto cleanup;
+
+ if (dbret == 0) {
+ edg_wll_IColumnsSQLPart(ctx, ctx->job_index_cols, stat, 1, &icnames, &icvalues);
+ trio_asprintf(&stmt,
+ "insert into states"
+ "(jobid,status,seq,int_status,version"
+ ",parent_job%s) "
+ "values ('%|Ss',%d,%d,'%|Ss','%|Ss','%|Ss'%s)",
+ icnames,
+ jobid_md5, stat->pub.state, seq, stat_enc,
+ INTSTAT_VERSION, parent_md5, icvalues);
+ free(icnames); free(icvalues);
+
+ if (edg_wll_ExecStmt(ctx,stmt,NULL) < 0) goto cleanup;
+ }
+
+ if (update) {
+ trio_asprintf(&stmt, "delete from states "
+ "where jobid ='%|Ss' and ( seq<%d or version !='%|Ss')",
+ jobid_md5, seq, INTSTAT_VERSION);
+ if (edg_wll_ExecStmt(ctx,stmt,NULL) < 0) goto cleanup;
+ }
+ if (update) {
+ trio_asprintf(&stmt, "delete from status_tags "
+ "where jobid ='%|Ss' and seq<%d", jobid_md5, seq);
+ if (edg_wll_ExecStmt(ctx,stmt,NULL) < 0) goto cleanup;
+ }
+
+ if (ctx->rgma_export) write2rgma_status(&stat->pub);
+
+cleanup:
+ free(stmt);
+ free(jobid_md5); free(stat_enc);
+ free(parent_md5);
+ return edg_wll_Error(ctx,NULL,NULL);
+}
+
+/*
+ * Retrieve stored job state from states and status_tags DB tables.
+ * Should be called with the job locked.
+ */
+
+edg_wll_ErrorCode edg_wll_LoadIntState(edg_wll_Context ctx,
+ edg_wlc_JobId jobid,
+ int seq,
+ intJobStat **stat)
+{
+ char *jobid_md5;
+ char *stmt;
+ edg_wll_Stmt sh;
+ char *res, *res_rest;
+ int nstates;
+
+ edg_wll_ResetError(ctx);
+ jobid_md5 = edg_wlc_JobIdGetUnique(jobid);
+
+ if (seq == -1) {
+ /* any sequence number */
+ trio_asprintf(&stmt,
+ "select int_status from states "
+ "where jobid='%|Ss' and version='%|Ss'",
+ jobid_md5, INTSTAT_VERSION);
+ } else {
+ trio_asprintf(&stmt,
+ "select int_status from states "
+ "where jobid='%|Ss' and seq='%d' and version='%|Ss'",
+ jobid_md5, seq, INTSTAT_VERSION);
+ }
+
+ if (stmt == NULL) {
+ return edg_wll_SetError(ctx, ENOMEM, NULL);
+ }
+
+ if ((nstates = edg_wll_ExecStmt(ctx,stmt,&sh)) < 0) goto cleanup;
+ if (nstates == 0) {
+ edg_wll_SetError(ctx,ENOENT,"no state in DB");
+ goto cleanup;
+ }
+ if (edg_wll_FetchRow(sh,&res) < 0) goto cleanup;
+
+ *stat = dec_intJobStat(res, &res_rest);
+ if (res_rest == NULL) {
+ edg_wll_SetError(ctx, EDG_WLL_ERROR_DB_CALL,
+ "error decoding DB intJobStatus");
+ }
+
+ free(res);
+cleanup:
+ free(jobid_md5);
+ free(stmt); edg_wll_FreeStmt(&sh);
+ return edg_wll_Error(ctx,NULL,NULL);
+}
+
+/*
+ * update stored state according to the new event
+ * (must be called with the job locked)
+ */
+
+edg_wll_ErrorCode edg_wll_StepIntState(edg_wll_Context ctx,
+ edg_wlc_JobId job,
+ edg_wll_Event *e,
+ int seq,
+ edg_wll_JobStat *stat_out)
+{
+ intJobStat *ijsp;
+ int intErr = 0;
+ int flags = 0;
+ int res;
+ int be_strict = 0;
+ char *errstring = NULL;
+ intJobStat jobstat;
+
+ if (seq != 0) {
+ intErr = edg_wll_LoadIntState(ctx, job, seq - 1, &ijsp);
+ }
+ if (seq != 0 && !intErr) {
+ res = processEvent(ijsp, e, seq, be_strict, &errstring);
+ if (res == RET_FATAL || res == RET_INTERNAL) { /* !strict */
+ return edg_wll_SetError(ctx, EINVAL, errstring);
+ }
+ edg_wll_StoreIntState(ctx, ijsp, seq);
+ if (stat_out) {
+ memcpy(stat_out,&ijsp->pub,sizeof *stat_out);
+ destroy_intJobStat_extension(ijsp);
+ }
+ else destroy_intJobStat(ijsp);
+ free(ijsp);
+ } else {
+ edg_wll_intJobStatus(ctx, job, flags,&jobstat, js_enable_store);
+ if (stat_out) {
+ memcpy(stat_out,&jobstat.pub,sizeof *stat_out);
+ destroy_intJobStat_extension(&jobstat);
+ }
+ else destroy_intJobStat(&jobstat);
+ }
+ return edg_wll_Error(ctx, NULL, NULL);
+}
--- /dev/null
+/* $Header$ */
+
+/*
+ * Internal representation of job state
+ * (includes edg_wll_JobStat API structure)
+ */
+
+#define INTSTAT_VERSION "release-2.0"
+
+
+typedef struct _intJobStat {
+ edg_wll_JobStat pub;
+ int wontresub;
+ char *last_seqcode;
+ char *last_cancel_seqcode;
+
+/* int expect_mask; */
+ } intJobStat;
+
+void destroy_intJobStat(intJobStat *);
+
+edg_wll_ErrorCode edg_wll_IColumnsSQLPart(edg_wll_Context, void *, intJobStat *, int , char **, char **);
+edg_wll_ErrorCode edg_wll_RefreshIColumns(edg_wll_Context, void *);
+int edg_wll_intJobStatus( edg_wll_Context, const edg_wlc_JobId, int, intJobStat *, int);
+
+intJobStat* dec_intJobStat(char *, char **);
+char *enc_intJobStat(char *, intJobStat* );
+
+void write2rgma_status(edg_wll_JobStat *);
+
--- /dev/null
+#ident "$Header$"
+
+#include <inttypes.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <assert.h>
+#include <stdarg.h>
+#include <regex.h>
+#include <syslog.h>
+
+#include "glite/wms/jobid/cjobid.h"
+#include "glite/lb/producer.h"
+#include "glite/lb/context-int.h"
+#include "glite/lb/trio.h"
+
+#include "store.h"
+#include "index.h"
+#include "jobstat.h"
+#include "lbs_db.h"
+#include "get_events.h"
+
+
+extern int debug;
+#ifndef dprintf
+#define dprintf(x) { if (debug) printf x; }
+#endif
+
+
+/* TBD: share in whole logging or workload */
+#ifdef __GNUC__
+#define UNUSED_VAR __attribute__((unused))
+#else
+#define UNUSED_VAR
+#endif
+
+static char* enc_strlist(char *, char **) UNUSED_VAR;
+static char **dec_strlist(char *, char **) UNUSED_VAR;
+
+/*
+ * string encoding routines for safe DB store
+ */
+
+static char *enc_string(char *old, char *item)
+{
+ char *out;
+ if (item == NULL) {
+ asprintf(&out,"%s-1 ", old);
+ } else {
+ asprintf(&out,"%s%d %s",old, strlen(item), item);
+ }
+ free(old);
+ return out;
+}
+
+static char *dec_string(char *in, char **rest)
+{
+ int scret;
+ int len = -1;
+ char *out;
+
+ scret = sscanf(in, "%d", &len);
+ if (scret < 1) {
+ *rest = NULL;
+ return NULL;
+ }
+ if (len == -1) {
+ out = NULL;
+ *rest = strchr(in, ' ') ? strchr(in, ' ') + 1 : NULL;
+ } else {
+ in = strchr(in, ' ') ? strchr(in, ' ') + 1 : NULL;
+ out = (char *)malloc(len+1);
+ if (out) {
+ memcpy(out, in, len);
+ *(out+len) = '\0';
+ }
+ *rest = in+len;
+ }
+ return out;
+}
+
+static char *enc_int(char *old, int item)
+{
+ char *out;
+ asprintf(&out,"%s%d ", old, item);
+ free(old);
+ return out;
+}
+
+static int dec_int(char* in, char **rest)
+{
+ int scret;
+ int out;
+
+ scret = sscanf(in, "%d", &out);
+ if (scret == 1) {
+ *rest = strchr(in, ' ') ? strchr(in, ' ') + 1 : NULL;
+ } else {
+ out = 0;
+ *rest = in;
+ }
+ return out;
+}
+
+static char* enc_jobid(char *old, edg_wlc_JobId item)
+{
+ char *str;
+ char *out;
+
+ str = edg_wlc_JobIdUnparse(item);
+ out = enc_string(old, str);
+ free(str);
+ return out;
+}
+static edg_wlc_JobId dec_jobid(char *in, char **rest)
+{
+ char *str;
+ edg_wlc_JobId jobid;
+
+ str = dec_string(in, rest);
+ if (str == NULL) return NULL;
+ edg_wlc_JobIdParse(str, &jobid);
+ free(str);
+ return jobid;
+}
+
+static char* enc_strlist(char *old, char **item)
+{
+ char *ret;
+
+ if (item == NULL) {
+ asprintf(&ret,"%s-1 ", old);
+ free(old);
+ return ret;
+ } else {
+ asprintf(&ret,"%s1 ",old);
+ free(old);
+ if (ret == NULL) return ret;
+ }
+ do {
+ ret = enc_string(ret, *item);
+ } while (*(item++) != NULL);
+ return ret;
+}
+
+static char **dec_strlist(char *in, char **rest)
+{
+ char **out;
+ int len = -1;
+ char *tmp_in, *tmp_ret;
+ int scret;
+
+ scret = sscanf(in, "%d", &len);
+ if (scret < 1) {
+ *rest = NULL;
+ return NULL;
+ }
+ if (len == -1) {
+ *rest = strchr(in, ' ') ? strchr(in, ' ') + 1 : NULL;
+ return NULL;
+ }
+
+ len = 0;
+ tmp_in = in = strchr(in, ' ') + 1 ;
+ do {
+ tmp_ret = dec_string(tmp_in, &tmp_in);
+ len++;
+ } while (tmp_ret != NULL);
+
+ out = (char**) malloc(len*sizeof(char*));
+
+ if (out) {
+ len = 0;
+ tmp_in = in;
+ do {
+ out[len] = dec_string(tmp_in, &tmp_in);
+ } while (out[len++] != NULL);
+ }
+ *rest = tmp_in;
+ return out;
+}
+
+static char* enc_taglist(char *old, edg_wll_TagValue *item)
+{
+ char *ret;
+
+ if (item == NULL) {
+ asprintf(&ret,"%s-1 ", old);
+ free(old);
+ return ret;
+ } else {
+ asprintf(&ret,"%s1 ",old);
+ free(old);
+ if (ret == NULL) return ret;
+ }
+ do {
+ ret = enc_string(ret, (*item).tag);
+ ret = enc_string(ret, (*item).value);
+ } while ((*(item++)).tag != NULL);
+ return ret;
+}
+
+static edg_wll_TagValue *dec_taglist(char *in, char **rest)
+{
+ edg_wll_TagValue *out;
+ int len = -1;
+ char *tmp_in, *tmp_ret, *tmp_ret2;
+ int scret;
+
+ scret = sscanf(in, "%d", &len);
+ if (scret < 1) {
+ *rest = NULL;
+ return NULL;
+ }
+ if (len == -1) {
+ *rest = strchr(in, ' ') ? strchr(in, ' ') + 1 : NULL;
+ return NULL;
+ }
+
+ len = 0;
+ tmp_in = in = strchr(in, ' ') + 1 ;
+ do {
+ tmp_ret2 = dec_string(tmp_in, &tmp_in);
+ if (!tmp_in) { *rest = tmp_in; return NULL; }
+ tmp_ret = dec_string(tmp_in, &tmp_in);
+ if (!tmp_in) { *rest = tmp_in; return NULL; }
+ len++;
+ } while (tmp_ret2 != NULL);
+
+ out = (edg_wll_TagValue *) malloc(len*sizeof(edg_wll_TagValue));
+
+ if (out) {
+ len = 0;
+ tmp_in = in;
+
+ do {
+ out[len].tag = dec_string(tmp_in, &tmp_in);
+ out[len].value = dec_string(tmp_in, &tmp_in);
+ } while (out[len++].tag != NULL);
+ *rest = tmp_in;
+ }
+ else
+ *rest = 0;
+
+ return out;
+}
+
+static char *enc_intlist(char *old, int *item)
+{
+ int len;
+ char *ret;
+
+ if (item == NULL) {
+ asprintf(&ret,"%s-1 ", old);
+ free(old);
+ return ret;
+ } else {
+ asprintf(&ret,"%s1 ",old);
+ free(old);
+ if (ret == NULL) return ret;
+ }
+ len = *item; item++;
+ ret = enc_int(ret, len);
+ for (; len > 0 ; len--, item++) {
+ ret = enc_int(ret, *item);
+ }
+
+ return ret;
+}
+
+static int *dec_intlist(char *in, char **rest)
+{
+ int len = -1;
+ int *out, *ptr;
+ char *tmp_in;
+ int scret;
+
+ scret = sscanf(in, "%d", &len);
+ if (scret < 1) {
+ *rest = NULL;
+ return NULL;
+ }
+ tmp_in = strchr(in, ' ') ? strchr(in, ' ') + 1 : NULL;
+ if (len == -1 || tmp_in == NULL) {
+ *rest = tmp_in;
+ return NULL;
+ }
+
+ len = dec_int(tmp_in, &tmp_in);
+ out = (int *)malloc( (len+1) *sizeof(int));
+ if (out) {
+ *out = len;
+ ptr = out+1;
+ while (len) {
+ *ptr = dec_int(tmp_in, &tmp_in);
+ len--; ptr++;
+ }
+ }
+ *rest = tmp_in;
+ return out;
+}
+
+static char* enc_timeval(char *old, struct timeval item)
+{
+ char *ret;
+
+ ret = enc_int(old, (int)item.tv_sec);
+ if (ret) {
+ ret = enc_int(ret, (int)item.tv_usec);
+ }
+ return ret;
+}
+
+static struct timeval dec_timeval(char *in, char **rest)
+{
+ struct timeval t;
+ char *tmp_in;
+
+ t.tv_sec = dec_int(in, &tmp_in);
+ if (tmp_in != NULL) t.tv_usec = dec_int(tmp_in, &tmp_in);
+ *rest = tmp_in;
+ return t;
+}
+
+static char *enc_JobStat(char *old, edg_wll_JobStat* stat)
+{
+ char *ret;
+
+ ret = enc_int(old, stat->state);
+ if (ret) ret = enc_jobid(ret, stat->jobId);
+ if (ret) ret = enc_string(ret, stat->owner);
+ if (ret) ret = enc_int(ret, stat->jobtype);
+ if (ret) ret = enc_jobid(ret, stat->parent_job);
+ if (ret) ret = enc_string(ret, stat->seed);
+ if (ret) ret = enc_int(ret, stat->children_num);
+ /* children data are not stored in DB */
+ if (ret) ret = enc_string(ret, stat->condorId);
+ if (ret) ret = enc_string(ret, stat->globusId);
+ if (ret) ret = enc_string(ret, stat->localId);
+ if (ret) ret = enc_string(ret, stat->jdl);
+ if (ret) ret = enc_string(ret, stat->matched_jdl);
+ if (ret) ret = enc_string(ret, stat->destination);
+ if (ret) ret = enc_string(ret, stat->condor_jdl);
+ if (ret) ret = enc_string(ret, stat->rsl);
+ if (ret) ret = enc_string(ret, stat->reason);
+ if (ret) ret = enc_string(ret, stat->location);
+ if (ret) ret = enc_string(ret, stat->ce_node);
+ if (ret) ret = enc_string(ret, stat->network_server);
+ if (ret) ret = enc_int(ret, stat->subjob_failed);
+ if (ret) ret = enc_int(ret, stat->done_code);
+ if (ret) ret = enc_int(ret, stat->exit_code);
+ if (ret) ret = enc_int(ret, stat->resubmitted);
+ if (ret) ret = enc_int(ret, stat->cancelling);
+ if (ret) ret = enc_string(ret, stat->cancelReason);
+ if (ret) ret = enc_int(ret, stat->cpuTime);
+ if (ret) ret = enc_taglist(ret, stat->user_tags);
+ if (ret) ret = enc_timeval(ret, stat->stateEnterTime);
+ if (ret) ret = enc_intlist(ret, stat->stateEnterTimes);
+ if (ret) ret = enc_timeval(ret, stat->lastUpdateTime);
+ if (ret) ret = enc_int(ret, stat->expectUpdate);
+ if (ret) ret = enc_string(ret, stat->expectFrom);
+
+ return ret;
+}
+static edg_wll_JobStat* dec_JobStat(char *in, char **rest)
+{
+ char *tmp_in;
+ edg_wll_JobStat *stat;
+
+ stat = (edg_wll_JobStat *) calloc(1,sizeof(edg_wll_JobStat));
+ if (!stat) return stat;
+
+ tmp_in = in;
+ stat->state = dec_int(tmp_in, &tmp_in);
+ if (tmp_in != NULL) stat->jobId = dec_jobid(tmp_in, &tmp_in);
+ if (tmp_in != NULL) stat->owner = dec_string(tmp_in, &tmp_in);
+ if (tmp_in != NULL) stat->jobtype = dec_int(tmp_in, &tmp_in);
+ if (tmp_in != NULL) stat->parent_job = dec_jobid(tmp_in, &tmp_in);
+ if (tmp_in != NULL) stat->seed = dec_string(tmp_in, &tmp_in);
+ if (tmp_in != NULL) stat->children_num = dec_int(tmp_in, &tmp_in);
+ /* children data are not stored in DB */
+ if (tmp_in != NULL) stat->condorId = dec_string(tmp_in, &tmp_in);
+ if (tmp_in != NULL) stat->globusId = dec_string(tmp_in, &tmp_in);
+ if (tmp_in != NULL) stat->localId = dec_string(tmp_in, &tmp_in);
+ if (tmp_in != NULL) stat->jdl = dec_string(tmp_in, &tmp_in);
+ if (tmp_in != NULL) stat->matched_jdl = dec_string(tmp_in, &tmp_in);
+ if (tmp_in != NULL) stat->destination = dec_string(tmp_in, &tmp_in);
+ if (tmp_in != NULL) stat->condor_jdl = dec_string(tmp_in, &tmp_in);
+ if (tmp_in != NULL) stat->rsl = dec_string(tmp_in, &tmp_in);
+ if (tmp_in != NULL) stat->reason = dec_string(tmp_in, &tmp_in);
+ if (tmp_in != NULL) stat->location = dec_string(tmp_in, &tmp_in);
+ if (tmp_in != NULL) stat->ce_node = dec_string(tmp_in, &tmp_in);
+ if (tmp_in != NULL) stat->network_server = dec_string(tmp_in, &tmp_in);
+ if (tmp_in != NULL) stat->subjob_failed = dec_int(tmp_in, &tmp_in);
+ if (tmp_in != NULL) stat->done_code = dec_int(tmp_in, &tmp_in);
+ if (tmp_in != NULL) stat->exit_code = dec_int(tmp_in, &tmp_in);
+ if (tmp_in != NULL) stat->resubmitted = dec_int(tmp_in, &tmp_in);
+ if (tmp_in != NULL) stat->cancelling = dec_int(tmp_in, &tmp_in);
+ if (tmp_in != NULL) stat->cancelReason = dec_string(tmp_in, &tmp_in);
+ if (tmp_in != NULL) stat->cpuTime = dec_int(tmp_in, &tmp_in);
+ if (tmp_in != NULL) stat->user_tags = dec_taglist(tmp_in, &tmp_in);
+ if (tmp_in != NULL) stat->stateEnterTime = dec_timeval(tmp_in, &tmp_in);
+ if (tmp_in != NULL) stat->stateEnterTimes = dec_intlist(tmp_in, &tmp_in);
+ if (tmp_in != NULL) stat->lastUpdateTime = dec_timeval(tmp_in, &tmp_in);
+ if (tmp_in != NULL) stat->expectUpdate = dec_int(tmp_in, &tmp_in);
+ if (tmp_in != NULL) stat->expectFrom = dec_string(tmp_in, &tmp_in);
+
+ *rest = tmp_in;
+ return stat;
+}
+
+char *enc_intJobStat(char *old, intJobStat* stat)
+{
+ char *ret;
+
+ ret = enc_JobStat(old, &stat->pub);
+ if (ret) ret = enc_int(ret, stat->wontresub);
+ if (ret) ret = enc_string(ret, stat->last_seqcode);
+ if (ret) ret = enc_string(ret, stat->last_cancel_seqcode);
+ return ret;
+}
+
+intJobStat* dec_intJobStat(char *in, char **rest)
+{
+ edg_wll_JobStat *pubstat;
+ intJobStat *stat = 0;
+ char *tmp_in;
+
+ pubstat = dec_JobStat(in, &tmp_in);
+ if (tmp_in != NULL) {
+ stat = (intJobStat *)calloc(1,sizeof(intJobStat));
+ }
+ if (stat != NULL) {
+ stat->pub = *pubstat;
+ free(pubstat);
+ stat->wontresub = dec_int(tmp_in, &tmp_in);
+ if (tmp_in != NULL) {
+ stat->last_seqcode = dec_string(tmp_in, &tmp_in);
+ }
+ if (tmp_in != NULL) {
+ stat->last_cancel_seqcode = dec_string(tmp_in, &tmp_in);
+ }
+ } else if (tmp_in != NULL) {
+ edg_wll_FreeStatus(pubstat);
+ free(pubstat);
+ }
+
+ *rest = tmp_in;
+ return stat;
+}
+
+/*
+ * Compute part of SQL command used for indexed state table columns
+ */
+
+edg_wll_ErrorCode edg_wll_IColumnsSQLPart(edg_wll_Context ctx,
+ void *job_index_cols_v,
+ intJobStat *stat,
+ int is_insert,
+ char **names_out,
+ char **values_out)
+{
+ int i;
+ char *names, *values;
+ char *data;
+ char *tmp;
+ edg_wll_IColumnRec *job_index_cols = (edg_wll_IColumnRec *)job_index_cols_v;
+
+ edg_wll_ResetError(ctx);
+
+ if (is_insert) names = strdup(""); else names = NULL;
+ values = strdup("");
+
+ if (job_index_cols != NULL)
+ for (i=0; job_index_cols[i].colname; i++) {
+ data = NULL;
+ switch (job_index_cols[i].qrec.attr) {
+ case EDG_WLL_QUERY_ATTR_OWNER:
+ if (stat->pub.owner)
+ trio_asprintf(&data, "'%|Ss'", stat->pub.owner);
+ else data = strdup("''");
+ break;
+ case EDG_WLL_QUERY_ATTR_LOCATION:
+ if (stat->pub.location)
+ trio_asprintf(&data, "'%|Ss'", stat->pub.location);
+ else data = strdup("''");
+ break;
+ case EDG_WLL_QUERY_ATTR_DESTINATION:
+ if (stat->pub.destination)
+ trio_asprintf(&data, "'%|Ss'", stat->pub.destination);
+ else data = strdup("''");
+ break;
+ case EDG_WLL_QUERY_ATTR_DONECODE:
+ asprintf(&data, "%d", stat->pub.done_code);
+ break;
+ case EDG_WLL_QUERY_ATTR_USERTAG:
+ if (stat->pub.user_tags) {
+ int k;
+ for (k=0; stat->pub.user_tags[k].tag &&
+ strcmp(stat->pub.user_tags[k].tag,job_index_cols[i].qrec.attr_id.tag);
+ k++);
+ if (stat->pub.user_tags[k].tag != NULL) {
+ trio_asprintf(&data, "'%|Ss'", stat->pub.user_tags[k].value);
+ } else data = strdup("''");
+ } else data = strdup("''");
+ break;
+ case EDG_WLL_QUERY_ATTR_TIME:
+ if (stat->pub.stateEnterTimes)
+ data = strdup(edg_wll_TimeToDB(stat->pub.stateEnterTimes[
+ job_index_cols[i].qrec.attr_id.state+1]));
+ else data = strdup("0");
+ break;
+ case EDG_WLL_QUERY_ATTR_RESUBMITTED:
+ asprintf(&data, "%d", stat->pub.resubmitted);
+ break;
+
+ /* XXX add more attributes when defined */
+ default:
+ /* do not use */
+ break;
+ }
+
+ if (!data) continue;
+
+ if (is_insert) {
+ asprintf(&tmp, "%s,`%s`", names, job_index_cols[i].colname);
+ free(names); names = tmp;
+ asprintf(&tmp, "%s,%s", values, data);
+ free(values); values = tmp;
+ } else {
+ /* update */
+ asprintf(&tmp, "%s,`%s`=%s", values, job_index_cols[i].colname, data);
+ free(values); values = tmp;
+ }
+ free(data);
+ }
+
+ if (is_insert) *names_out = names;
+ *values_out = values;
+
+ return edg_wll_Error(ctx, NULL, NULL);
+}
+
+
+/*
+ * Set values of index columns in state table (after index reconfiguration)
+ */
+
+edg_wll_ErrorCode edg_wll_RefreshIColumns(edg_wll_Context ctx, void *job_index_cols) {
+
+ edg_wll_Stmt sh, sh2;
+ int njobs, ret = -1;
+ intJobStat *stat;
+ edg_wlc_JobId jobid;
+ char *res[5];
+ char *rest;
+ char *icvalues, *stmt;
+ int i;
+
+ edg_wll_ResetError(ctx);
+ if (!job_index_cols) return 0;
+
+ if ((njobs = edg_wll_ExecStmt(ctx, "select s.jobid,s.int_status,s.seq,s.version,j.dg_jobid"
+ " from states s, jobs j where s.jobid=j.jobid",&sh)) < 0) {
+ edg_wll_FreeStmt(&sh);
+ return edg_wll_Error(ctx, NULL, NULL);
+ }
+ while ((ret=edg_wll_FetchRow(sh,res)) >0) {
+ if (strcmp(res[3], INTSTAT_VERSION)) {
+ stat = NULL;
+ if (!edg_wlc_JobIdParse(res[4], &jobid)) {
+ if ((stat = malloc(sizeof(intJobStat))) != NULL) {
+ if (edg_wll_intJobStatus(ctx, jobid, 0, stat, 1)) {
+ free(stat);
+ stat = NULL;
+ }
+ }
+ edg_wlc_JobIdFree(jobid);
+ }
+ } else {
+ stat = dec_intJobStat(res[1], &rest);
+ if (rest == NULL) stat = NULL;
+ }
+ if (stat == NULL) {
+ edg_wll_FreeStmt(&sh);
+ return edg_wll_SetError(ctx, EDG_WLL_ERROR_SERVER_RESPONSE,
+ "cannot decode int_status from states DB table");
+ }
+
+ edg_wll_IColumnsSQLPart(ctx, job_index_cols, stat, 0, NULL, &icvalues);
+ trio_asprintf(&stmt, "update states set seq=%s%s where jobid='%|Ss'", res[2], icvalues, res[0]);
+ ret = edg_wll_ExecStmt(ctx, stmt, &sh2);
+ edg_wll_FreeStmt(&sh2);
+
+ for (i = 0; i < 5; i++) free(res[i]);
+ destroy_intJobStat(stat); free(stat);
+ free(stmt); free(icvalues);
+
+ if (ret < 0) return edg_wll_Error(ctx, NULL, NULL);
+
+ }
+ edg_wll_FreeStmt(&sh);
+ return edg_wll_Error(ctx, NULL, NULL);
+}
+
+
+int edg_wll_compare_seq(const char *a, const char *b)
+{
+ unsigned int c[EDG_WLL_SOURCE__LAST];
+ unsigned int d[EDG_WLL_SOURCE__LAST];
+ int res, i;
+
+ assert(EDG_WLL_SOURCE__LAST == 9);
+
+ res = sscanf(a, "UI=%d:NS=%d:WM=%d:BH=%d:JSS=%d:LM=%d:LRMS=%d:APP=%d",
+ &c[EDG_WLL_SOURCE_USER_INTERFACE],
+ &c[EDG_WLL_SOURCE_NETWORK_SERVER],
+ &c[EDG_WLL_SOURCE_WORKLOAD_MANAGER],
+ &c[EDG_WLL_SOURCE_BIG_HELPER],
+ &c[EDG_WLL_SOURCE_JOB_SUBMISSION],
+ &c[EDG_WLL_SOURCE_LOG_MONITOR],
+ &c[EDG_WLL_SOURCE_LRMS],
+ &c[EDG_WLL_SOURCE_APPLICATION]);
+ if (res != EDG_WLL_SOURCE__LAST-1) {
+ syslog(LOG_ERR, "unparsable sequence code %s\n", a);
+ dprintf(( "unparsable sequence code %s\n", a));
+ return -1;
+ }
+
+ res = sscanf(b, "UI=%d:NS=%d:WM=%d:BH=%d:JSS=%d:LM=%d:LRMS=%d:APP=%d",
+ &d[EDG_WLL_SOURCE_USER_INTERFACE],
+ &d[EDG_WLL_SOURCE_NETWORK_SERVER],
+ &d[EDG_WLL_SOURCE_WORKLOAD_MANAGER],
+ &d[EDG_WLL_SOURCE_BIG_HELPER],
+ &d[EDG_WLL_SOURCE_JOB_SUBMISSION],
+ &d[EDG_WLL_SOURCE_LOG_MONITOR],
+ &d[EDG_WLL_SOURCE_LRMS],
+ &d[EDG_WLL_SOURCE_APPLICATION]);
+ if (res != EDG_WLL_SOURCE__LAST-1) {
+ syslog(LOG_ERR, "unparsable sequence code %s\n", b);
+ dprintf(( "unparsable sequence code %s\n", b));
+ return 1;
+ }
+
+ for (i = EDG_WLL_SOURCE_USER_INTERFACE ; i < EDG_WLL_SOURCE__LAST; i++) {
+ if (c[i] < d[i]) return -1;
+ if (c[i] > d[i]) return 1;
+ }
+
+ return 0;
+}
+
+static int compare_events_by_seq(const void *a, const void *b)
+{
+ const edg_wll_Event *e = (edg_wll_Event *)a;
+ const edg_wll_Event *f = (edg_wll_Event *)b;
+
+ return edg_wll_compare_seq(e->any.seqcode, f->any.seqcode);
+}
+
+void edg_wll_SortEvents(edg_wll_Event *e)
+{
+ int n;
+
+ if (!e) return;
+ for (n=0; e[n].type; n++);
+ qsort(e,n,sizeof *e,compare_events_by_seq);
+}
--- /dev/null
+#ident "$Header$"
+
+#include <string.h>
+#include <unistd.h>
+#include <errno.h>
+#include <syslog.h>
+
+#include <voms_apic.h>
+#include <openssl/ssl.h>
+#include <libxml/parser.h>
+#undef WITHOUT_TRIO
+
+#include "glite/wms/jobid/strmd5.h"
+#include "glite/wms/jobid/cjobid.h"
+#include "glite/lb/producer.h"
+#include "glite/lb/trio.h"
+#include "lb_authz.h"
+#include "lbs_db.h"
+
+GACLentry *GACLparseEntry(xmlNodePtr cur);
+
+static int
+add_groups(edg_wll_Context ctx, struct voms *voms_cert, char *vo_name,
+ edg_wll_VomsGroups *groups)
+{
+ struct data **voms_data;
+ edg_wll_VomsGroup *tmp = NULL;
+
+ if (voms_cert->type != TYPE_STD) {
+ edg_wll_SetError(ctx, EINVAL, "not supported VOMS certificate type");
+ return EINVAL;
+ }
+
+ for (voms_data = voms_cert->std; voms_data && *voms_data; voms_data++) {
+ if ((*voms_data)->group && *(*voms_data)->group) {
+ tmp = realloc(groups->val, (groups->len + 1) * sizeof(*groups->val));
+ if (tmp == NULL)
+ return ENOMEM;
+ groups->val = tmp;
+ groups->val[groups->len].vo = strdup(vo_name);
+ groups->val[groups->len].name = strdup((*voms_data)->group);
+ groups->len++;
+ }
+ }
+ return 0;
+}
+
+static int
+get_groups(edg_wll_Context ctx, struct vomsdata *voms_info,
+ edg_wll_VomsGroups *res_groups)
+{
+ struct voms **voms_cert = NULL;
+ edg_wll_VomsGroups groups;
+ int ret;
+
+ memset(&groups, 0, sizeof(groups));
+
+ for (voms_cert = voms_info->data; voms_cert && *voms_cert; voms_cert++) {
+ if ((*voms_cert)->voname) {
+ ret = add_groups(ctx, *voms_cert, (*voms_cert)->voname, &groups);
+ if (ret) {
+ edg_wll_FreeVomsGroups(&groups);
+ return ret;
+ }
+ }
+ }
+
+ res_groups->len = groups.len;
+ res_groups->val = groups.val;
+ return 0;
+}
+
+int
+edg_wll_GetVomsGroups(edg_wll_Context ctx, char *voms_dir, char *ca_dir)
+{
+ STACK_OF(X509) *p_chain = NULL;
+ X509 *cert = NULL;
+ int ret;
+ int err = 0;
+ struct vomsdata *voms_info = NULL;
+
+ memset (&ctx->vomsGroups, 0, sizeof(ctx->vomsGroups));
+ edg_wll_ResetError(ctx);
+
+ p_chain = SSL_get_peer_cert_chain(ctx->connPool[ctx->connToUse].ssl);
+ cert = SSL_get_peer_certificate(ctx->connPool[ctx->connToUse].ssl);
+
+ /* exit if peer's credentials are not available */
+ if (p_chain == NULL || cert == NULL) {
+ ret = 0;
+ goto end;
+ }
+
+ /* uses X509_CERT_DIR and X509_VOMS_DIR vars */
+ voms_info = VOMS_Init(voms_dir, ca_dir);
+ if (voms_info == NULL) {
+ edg_wll_SetError(ctx, errno, "failed to initialize VOMS structures");
+ ret = -1; /* XXX VOMS Error */
+ goto end;
+ }
+
+ ret = VOMS_Retrieve(cert, p_chain, RECURSE_CHAIN, voms_info, &err);
+ if (ret == 0) {
+ if (err == VERR_NOEXT)
+ edg_wll_SetError(ctx, EINVAL, "no client VOMS certificates found");
+ else {
+ edg_wll_SetError(ctx, -1, "failed to retrieve VOMS info");
+ ret = -1; /* XXX VOMS Error */
+ }
+ goto end;
+ }
+
+ ret = get_groups(ctx, voms_info, &ctx->vomsGroups);
+
+end:
+ if (voms_info)
+ VOMS_Destroy(voms_info);
+ if (cert)
+ X509_free(cert);
+
+ return ret;
+}
+
+void
+edg_wll_FreeVomsGroups(edg_wll_VomsGroups *groups)
+{
+ size_t len;
+
+ if (groups == NULL)
+ return;
+
+ for (len = 0; len < groups->len; len++) {
+ if (groups->val[len].vo)
+ free(groups->val[len].vo);
+ if (groups->val[len].name)
+ free(groups->val[len].name);
+ }
+}
+
+
+static int
+parse_creds(edg_wll_VomsGroups *groups, char *subject, GACLuser **gacl_user)
+{
+ GACLcred *cred = NULL;
+ GACLuser *user = NULL;
+ int ret;
+ int i;
+
+ GACLinit();
+
+ cred = GACLnewCred("person");
+ if (cred == NULL)
+ return ENOMEM;
+
+ if (!GACLaddToCred(cred, "dn", subject)) {
+ ret = EINVAL; /* GACL_ERR */
+ goto fail;
+ }
+
+ user = GACLnewUser(cred);
+ if (user == NULL) {
+ ret = ENOMEM;
+ goto fail;
+ }
+ cred = NULL; /* GACLnewUser() doesn't copy content, just store the pointer */
+
+ for (i = 0; i < groups->len; i++) {
+ cred = GACLnewCred("voms-cred");
+ if (cred == NULL) {
+ ret = ENOMEM;
+ goto fail;
+ }
+ if (!GACLaddToCred(cred, "vo", groups->val[i].vo) ||
+ !GACLaddToCred(cred, "group", groups->val[i].name)) {
+ ret = EINVAL; /* GACL_ERR */
+ goto fail;
+ }
+ if (!GACLuserAddCred(user, cred)) {
+ ret = EINVAL; /* GACL_ERR */
+ goto fail;
+ }
+ cred = NULL;
+ /* GACLuserAddCred() doesn't copy content, just store the pointer. Cred
+ * mustn't be free()ed */
+ }
+
+ *gacl_user = user;
+
+ return 0;
+
+fail:
+ if (cred)
+ GACLfreeCred(cred);
+ if (user)
+ GACLfreeUser(user);
+
+ return ret;
+}
+
+static int
+cmp_gacl_names(struct _GACLnamevalue *n1, struct _GACLnamevalue *n2)
+{
+ if (n1 == NULL && n2 == NULL)
+ return 1;
+
+ for ( ; n1; n1 = n1->next, n2 = n2->next) {
+ if (n2 == NULL)
+ return 0;
+ if (strcmp(n1->name, n2->name) != 0 ||
+ strcmp(n1->value, n2->value) != 0)
+ return 0;
+ }
+
+ return (n2 == NULL);
+}
+
+static int
+cmp_gacl_creds(GACLcred *c1, GACLcred *c2)
+{
+ if (strcmp(c1->type, c2->type) != 0)
+ return 0;
+
+ return cmp_gacl_names(c1->firstname, c2->firstname);
+ /* we support only "simple" entries containing only one credential (DN or
+ * VOMS group */
+}
+
+static int
+addEntry(GACLacl *acl, GACLentry *entry)
+{
+ GACLentry *cur = NULL;
+
+
+ if ( acl == NULL )
+ return EINVAL;
+
+ if ( acl->firstentry == NULL )
+ return (GACLaddEntry(acl, entry) == 0) ? -1 /* GACL_ERR */ : 0;
+
+ for ( cur = acl->firstentry; cur; cur = cur->next )
+ if ( cmp_gacl_creds(cur->firstcred, entry->firstcred)
+ && cur->allowed == entry->allowed
+ && cur->denied == entry->denied )
+ return EEXIST;
+
+ return (GACLaddEntry(acl, entry) == 0) ? -1 /* GACL_ERR */ : 0;
+}
+
+static int
+delEntry(GACLacl *acl, GACLentry *entry)
+{
+ GACLentry *cur = NULL, *prev = NULL;
+ int found = 0;
+
+ if (acl == NULL || acl->firstentry == NULL)
+ return EINVAL;
+
+ cur = acl->firstentry;
+ while (cur) {
+ if (cmp_gacl_creds(cur->firstcred, entry->firstcred) &&
+ cur->allowed == entry->allowed &&
+ cur->denied == entry->denied) {
+ if (prev)
+ prev->next = cur->next;
+ else
+ acl->firstentry = cur->next;
+ GACLfreeEntry(cur);
+ found = 1;
+ break;
+ }
+ prev = cur;
+ cur = cur->next;
+ }
+
+ return (found) ? 0 : -1 /* NOT_FOUND */;
+}
+
+static int
+create_cred(char *userid, int user_type, GACLcred **cred)
+{
+ GACLcred *c = NULL;
+ char *group = NULL;
+
+ if (user_type == EDG_WLL_USER_SUBJECT) {
+ c = GACLnewCred("person");
+ if (c == NULL)
+ return ENOMEM;
+ if (!GACLaddToCred(c, "dn", userid)) {
+ GACLfreeCred(c);
+ return -1; /* GACL_ERR */
+ }
+ } else if(user_type == EDG_WLL_USER_VOMS_GROUP) {
+ c = GACLnewCred("voms-cred");
+ if (c == NULL)
+ return ENOMEM;
+ group = strchr(userid, ':');
+ if ( !group )
+ return EINVAL;
+ *group++ = '\0';
+ if (!GACLaddToCred(c, "vo", userid) ||
+ !GACLaddToCred(c, "group", group)) {
+ GACLfreeCred(c);
+ return -1; /* GACL_ERR */
+ }
+ } else
+ return EINVAL;
+
+ *cred = c;
+
+ return 0;
+}
+
+static int
+change_acl(GACLacl *acl, GACLentry *entry, int operation)
+ /* creds, permission, permission_type */
+{
+ if (operation == EDG_WLL_ACL_ADD)
+ return addEntry(acl, entry);
+
+ if (operation == EDG_WLL_ACL_REMOVE)
+ return delEntry(acl, entry);
+
+ return -1;
+}
+
+static int
+edg_wll_change_acl(edg_wll_Acl acl, char *user_id, int user_id_type,
+ int permission, int perm_type, int operation)
+{
+ GACLcred *cred = NULL;
+ GACLentry *entry = NULL;
+ int ret;
+
+ GACLinit();
+
+ if (acl == NULL || acl->value == NULL)
+ return EINVAL;
+
+ ret = create_cred(user_id, user_id_type, &cred);
+ if (ret)
+ return ret;
+
+ entry = GACLnewEntry();
+ if (entry == NULL) {
+ ret = ENOMEM;
+ goto end;
+ }
+
+ if (!GACLaddCred(entry, cred)) {
+ ret = -1; /* GACLErr */
+ goto end;
+ }
+
+ if (perm_type == EDG_WLL_PERM_ALLOW)
+ GACLallowPerm(entry, permission);
+ else if (perm_type == EDG_WLL_PERM_DENY)
+ GACLdenyPerm(entry, permission);
+ else {
+ ret = EINVAL;
+ goto end;
+ }
+
+ ret = change_acl(acl->value, entry, operation);
+ if (ret)
+ {
+/* XXX: mem leak?
+ GACLfreeEntry(entry);
+*/
+ goto end;
+ }
+
+ if (acl->string) free(acl->string);
+ ret = edg_wll_EncodeACL(acl->value, &acl->string);
+
+end:
+
+ return ret;
+}
+
+int
+edg_wll_CheckACL(edg_wll_Context ctx, edg_wll_Acl acl, int requested_perm)
+{
+ int ret;
+ GACLuser *user = NULL;
+ GACLperm perm;
+
+ if (acl == NULL || acl->value == NULL)
+ return edg_wll_SetError(ctx,EINVAL,"CheckACL");
+
+ if (!ctx->peerName) return edg_wll_SetError(ctx,EPERM,"CheckACL");
+
+ ret = parse_creds(&ctx->vomsGroups, ctx->peerName, &user);
+ if (ret) {
+ return edg_wll_SetError(ctx,ret,"parse_creds()");
+ }
+
+ perm = GACLtestUserAcl(acl->value, user);
+
+ GACLfreeUser(user);
+
+ if (perm & requested_perm) return edg_wll_ResetError(ctx);
+ else return edg_wll_SetError(ctx,EPERM,"CheckACL");
+}
+
+int
+edg_wll_EncodeACL(GACLacl *acl, char **str)
+{
+ int tmp_fd, ret;
+ FILE *fd = NULL;
+ char filename[16];
+ char line[4096];
+ char *buf = NULL;
+ size_t buf_len = 0;
+ char *p;
+
+ snprintf(filename, sizeof(filename), "/tmp/XXXXXX");
+ tmp_fd = mkstemp(filename);
+ if (tmp_fd == -1)
+ return errno;
+
+ fd = fdopen(tmp_fd, "r");
+
+ ret = GACLsaveAcl(filename, acl);
+ unlink(filename);
+ if (ret == 0) {
+ ret = -1; /* GACL_ERR */
+ goto end;
+ }
+
+ buf_len = 1024;
+ buf = calloc(buf_len, 1);
+ if (buf == NULL) {
+ ret = ENOMEM;
+ goto end;
+ }
+
+ while (fgets(line, sizeof(line), fd) != NULL) {
+ p = strchr(line, '\n');
+ if (p)
+ *p = '\0';
+
+ if (strlen(buf) + strlen(line) > buf_len) {
+ char *tmp;
+
+ tmp = realloc(buf, buf_len + 1024);
+ if (tmp == NULL) {
+ ret = ENOMEM;
+ goto end;
+ }
+ buf = tmp;
+ buf_len += 1024;
+ }
+
+ strcat(buf, line);
+ }
+
+ *str = buf;
+ ret = 0;
+
+end:
+ fclose(fd);
+ return ret;
+}
+
+int
+edg_wll_DecodeACL(char *buf, GACLacl **result_acl)
+{
+ /* Got from GACLloadAcl() available from GACL API */
+ xmlDocPtr doc;
+ xmlNodePtr cur;
+ GACLacl *acl;
+ GACLentry *entry;
+
+ doc = xmlParseMemory(buf, strlen(buf));
+ if (doc == NULL) return EINVAL;
+
+ cur = xmlDocGetRootElement(doc);
+
+ if (xmlStrcmp(cur->name, (const xmlChar *) "gacl"))
+ {
+ free(doc);
+ free(cur);
+ return EINVAL;
+ }
+
+ cur = cur->xmlChildrenNode;
+
+ acl = GACLnewAcl();
+
+ while (cur != NULL)
+ {
+ /*
+ if (cur->type == XML_TEXT_NODE && cur->content == '\n') {
+ cur=cur->next;
+ continue;
+ }
+ */
+ entry = GACLparseEntry(cur);
+ if (entry == NULL)
+ {
+ GACLfreeAcl(acl);
+ xmlFreeDoc(doc);
+ return EINVAL;
+ }
+
+ GACLaddEntry(acl, entry);
+
+ cur=cur->next;
+ }
+
+ xmlFreeDoc(doc);
+ *result_acl = acl;
+ return 0;
+}
+
+int
+edg_wll_InitAcl(edg_wll_Acl *acl)
+{
+ edg_wll_Acl tmp;
+
+ tmp = malloc(sizeof(*tmp));
+ if ( !tmp )
+ return ENOMEM;
+
+ tmp->value = GACLnewAcl();
+ tmp->string = NULL;
+ *acl = tmp;
+ return 0;
+}
+
+void
+edg_wll_FreeAcl(edg_wll_Acl acl)
+{
+ if ( acl->value ) GACLfreeAcl(acl->value);
+ if ( acl->string ) free(acl->string);
+ free(acl);
+}
+
+int
+edg_wll_HandleCounterACL(edg_wll_Context ctx, edg_wll_Acl acl,
+ char *aclid, int incr)
+{
+ char *q1 = NULL,
+ *q2 = NULL;
+
+ edg_wll_ResetError(ctx);
+
+ if ( incr > 0 )
+ {
+ trio_asprintf(&q1,
+ "insert into acls(aclid,value,refcnt) "
+ "values ('%|Ss','%|Ss',%d)",
+ aclid, acl->string, incr);
+
+ for ( ; ; )
+ {
+ if ( edg_wll_ExecStmt(ctx, q1, NULL) > 0 )
+ goto end;
+
+ if ( edg_wll_Error(ctx,NULL,NULL) != EEXIST )
+ goto end;
+
+ /*
+ * row allready in DB
+ */
+ if ( !q2 ) trio_asprintf(&q2,
+ "update acls set refcnt = refcnt+%d "
+ "where aclid = '%|Ss'",
+ incr, aclid);
+ if ( edg_wll_ExecStmt(ctx, q2, NULL) < 0 )
+ continue;
+
+ goto end;
+ }
+ }
+ else if (incr < 0)
+ {
+ trio_asprintf(&q1,
+ "update acls set refcnt = refcnt-%d "
+ "where aclid='%|Ss' and refcnt>=%d",
+ -incr, aclid, -incr);
+
+ if ( edg_wll_ExecStmt(ctx, q1, NULL) > 0 )
+ {
+ trio_asprintf(&q2,
+ "delete from acls "
+ "where aclid='%|Ss' and refcnt=0",
+ aclid);
+ edg_wll_ExecStmt(ctx, q2, NULL);
+ }
+ else
+ {
+ fprintf(stderr, "ACL with ID: %s has invalid reference count\n", aclid);
+ syslog(LOG_WARNING, "ACL with ID: %s has invalid reference count\n", aclid);
+ }
+ }
+
+
+end:
+ if ( q1 ) free(q1);
+ if ( q2 ) free(q2);
+
+ return edg_wll_Error(ctx, NULL, NULL);
+}
+
+int
+edg_wll_UpdateACL(edg_wll_Context ctx, edg_wlc_JobId job,
+ char *user_id, int user_id_type,
+ int permission, int perm_type, int operation)
+{
+ char *md5_jobid;
+ edg_wll_Acl acl = NULL;
+ int ret;
+ char *stmt = NULL;
+ char *new_aclid = NULL, *old_aclid = NULL;
+ int updated;
+
+ edg_wll_ResetError(ctx);
+
+ md5_jobid = edg_wlc_JobIdGetUnique(job);
+
+ do {
+ if (acl)
+ {
+ edg_wll_FreeAcl(acl);
+ acl = NULL;
+ }
+ if (old_aclid)
+ {
+ free(old_aclid);
+ old_aclid = NULL;
+ }
+ if (new_aclid)
+ {
+ free(new_aclid);
+ new_aclid = NULL;
+ }
+
+ if ( (ret = edg_wll_GetACL(ctx, job, &acl)) )
+ goto end;
+ if ( !acl && (ret = edg_wll_InitAcl(&acl)) )
+ goto end;
+
+ old_aclid = acl->string? strdup(strmd5(acl->string, NULL)): NULL;
+
+ ret = edg_wll_change_acl(acl, user_id, user_id_type,
+ permission, perm_type, operation);
+ if (ret)
+ {
+ if ( ret == EEXIST )
+ /*
+ * adding allready set entry
+ * only upgrade the counter
+ */
+ ret = edg_wll_HandleCounterACL(ctx, acl, new_aclid, 1);
+
+ goto end;
+ }
+
+ new_aclid = strdup(strmd5(acl->string, NULL));
+
+ /* store new ACL or increment its counter if already present in db */
+ ret = edg_wll_HandleCounterACL(ctx, acl, new_aclid, 1);
+ if (ret)
+ goto end;
+
+ if ( old_aclid )
+ trio_asprintf(&stmt,
+ "update jobs set aclid='%|Ss' where jobid='%|Ss' and aclid='%|Ss'",
+ new_aclid, md5_jobid, old_aclid);
+ else
+ trio_asprintf(&stmt,
+ "update jobs set aclid='%|Ss' where jobid='%|Ss' and ISNULL(aclid)",
+ new_aclid, md5_jobid);
+ updated = edg_wll_ExecStmt(ctx, stmt, NULL);
+ free(stmt); stmt = NULL;
+
+ if (updated > 0)
+ /* decrement reference counter of the old ACL, and possibly remove
+ * whole ACL if the counter becames zero */
+ ret = edg_wll_HandleCounterACL(ctx, NULL, old_aclid, -1);
+ else
+ /* We failed to store new ACL to db, most likely because the ACL has
+ * been changed. Decrement counter of new ACL set before trying
+ * updating */
+ ret = edg_wll_HandleCounterACL(ctx, NULL, new_aclid, -1);
+ } while (updated <= 0);
+
+end:
+ free(md5_jobid);
+ if (acl)
+ edg_wll_FreeAcl(acl);
+ if (new_aclid)
+ free(new_aclid);
+ if (old_aclid)
+ free(old_aclid);
+
+ return ret;
+}
+
+int edg_wll_GetACL(edg_wll_Context ctx, edg_wlc_JobId jobid, edg_wll_Acl *acl)
+{
+ char *q = NULL;
+ char *acl_id = NULL;
+ char *acl_str = NULL;
+ edg_wll_Stmt stmt = NULL;
+ int ret;
+ GACLacl *gacl = NULL;
+ char *jobstr = edg_wlc_JobIdGetUnique(jobid);
+
+ if (jobid == NULL || jobstr == NULL)
+ return edg_wll_SetError(ctx,EINVAL,"edg_wll_GetACL()");
+
+ edg_wll_ResetError(ctx);
+
+ trio_asprintf(&q,
+ "select aclid from jobs where jobid = '%|Ss'", jobstr);
+
+ if (edg_wll_ExecStmt(ctx, q, &stmt) < 0 ||
+ edg_wll_FetchRow(stmt, &acl_id) < 0) {
+ goto end;
+ }
+ edg_wll_FreeStmt(&stmt); stmt = NULL;
+ free(q); q = NULL;
+
+ if (acl_id == NULL || *acl_id == '\0') {
+ *acl = NULL;
+ return 0;
+ }
+
+ trio_asprintf(&q,
+ "select value from acls where aclid = '%|Ss'", acl_id);
+ if (edg_wll_ExecStmt(ctx, q, &stmt) < 0 ||
+ edg_wll_FetchRow(stmt, &acl_str) < 0) {
+ goto end;
+ }
+
+ ret = edg_wll_DecodeACL(acl_str, &gacl);
+ if (ret) {
+ edg_wll_SetError(ctx, EINVAL, "encoding ACL");
+ goto end;
+ }
+
+ *acl = calloc(1, sizeof(**acl));
+ if (*acl == NULL) {
+ ret = ENOMEM;
+ edg_wll_SetError(ctx, ENOMEM, "not enough memory");
+ goto end;
+ }
+
+ (*acl)->value = gacl;
+ (*acl)->string = acl_str;
+ gacl = NULL; acl_str = NULL;
+ ret = 0;
+
+end:
+ if (q) free(q);
+ if (stmt) edg_wll_FreeStmt(&stmt);
+ if (acl_id) free(acl_id);
+ if (acl_str) free(acl_str);
+ if (gacl) GACLfreeAcl(gacl);
+ if (jobstr) free(jobstr);
+
+ return edg_wll_Error(ctx, NULL, NULL);
+}
--- /dev/null
+#ifndef LB_AUTHZ_H
+#define LB_AUTHZ_H
+
+#include <stdio.h>
+#include <gacl.h>
+
+#include "glite/lb/context-int.h"
+
+typedef struct _edg_wll_Acl {
+ GACLacl *value;
+ char *string;
+} _edg_wll_Acl;
+typedef struct _edg_wll_Acl *edg_wll_Acl;
+
+extern int
+edg_wll_InitAcl(edg_wll_Acl *);
+
+extern void
+edg_wll_FreeAcl(edg_wll_Acl);
+
+extern int
+edg_wll_GetVomsGroups(edg_wll_Context, char *, char *);
+
+extern void
+edg_wll_FreeVomsGroups(edg_wll_VomsGroups *);
+
+extern int
+edg_wll_UpdateACL(edg_wll_Context, edg_wlc_JobId, char *, int, int, int, int);
+
+extern int
+edg_wll_CheckACL(edg_wll_Context, edg_wll_Acl, int);
+
+extern int
+edg_wll_DecodeACL(char *, GACLacl **);
+
+extern int
+edg_wll_EncodeACL(GACLacl *, char **);
+
+extern int
+edg_wll_GetACL(edg_wll_Context, edg_wlc_JobId, edg_wll_Acl *);
+
+#endif
--- /dev/null
+#ident "$Header$"
+
+#include "lb_html.h"
+#include "lb_proto.h"
+
+#include "glite/lb/consumer.h"
+#include "glite/lb/context-int.h"
+
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#ifdef __GNUC__
+#define UNUSED_VAR __attribute__((unused))
+#else
+#define UNUSED_VAR
+#endif
+
+int edg_wll_QueryToHTML(edg_wll_Context ctx UNUSED_VAR, edg_wll_Event *eventsOut UNUSED_VAR, char **message UNUSED_VAR)
+{
+/* not implemented yet */
+ return -1;
+}
+
+/* construct Message-Body of Response-Line for edg_wll_UserJobs */
+int edg_wll_UserJobsToHTML(edg_wll_Context ctx, edg_wlc_JobId *jobsOut, char **message)
+{
+ char *pomA, *pomB;
+ int i = 0;
+
+ /* head */
+ pomB = strdup("");
+
+ while (jobsOut[i]) {
+ char *chid = edg_wlc_JobIdUnparse(jobsOut[i]);
+
+ asprintf(&pomA,"%s\t\t <li> <a href=\"%s\">%s</a>\r\n",
+ pomB, chid,chid);
+
+ free(chid);
+ free(pomB);
+ pomB = pomA;
+ i++;
+ }
+
+ asprintf(&pomA, "<html>\r\n\t<body>\r\n"
+ "<h2><B>User jobs</B></h2>\r\n"
+ "User subject: %s<p>"
+ "<ul>%s</ul>"
+ "\t</body>\r\n</html>",ctx->peerName,pomB);
+ free(pomB);
+
+ *message = pomA;
+
+ return 0;
+}
+
+
+/* construct Message-Body of Response-Line for edg_wll_JobStatus */
+int edg_wll_JobStatusToHTML(edg_wll_Context ctx UNUSED_VAR, edg_wll_JobStat stat, char **message)
+{
+ char *pomA, *pomB;
+ char *chid,*chstat;
+ char *jdl,*rsl;
+
+ jdl = strdup("");
+ rsl = strdup("");
+
+ pomB = strdup("");
+
+ chid = edg_wlc_JobIdUnparse(stat.jobId);
+
+#define TR(name,type,field) \
+ if (field) { \
+ asprintf(&pomA,"%s<tr><th align=\"left\">" name ":</th>" \
+ "<td>" type "</td></tr>",pomB,(field)); \
+ free(pomB); \
+ pomB = pomA; \
+ }
+
+ TR("Status","%s",(chstat = edg_wll_StatToString(stat.state)));
+ free(chstat);
+ TR("owner","%s",stat.owner);
+ TR("Condor Id","%s",stat.condorId);
+ TR("Globus Id","%s",stat.globusId);
+ TR("Local Id","%s",stat.localId);
+ TR("Reason","%s",stat.reason);
+ if ( (stat.stateEnterTime.tv_sec) || (stat.stateEnterTime.tv_usec) ) {
+ time_t time = stat.stateEnterTime.tv_sec;
+ TR("State entered","%s",ctime(&time));
+ }
+ if ( (stat.lastUpdateTime.tv_sec) || (stat.lastUpdateTime.tv_usec) ) {
+ time_t time = stat.lastUpdateTime.tv_sec;
+ TR("Last update","%s",ctime(&time));
+ }
+ TR("Expect update","%s",stat.expectUpdate ? "YES" : "NO");
+ TR("Expect update from","%s",stat.expectFrom);
+ TR("Location","%s",stat.location);
+ TR("Destination","%s",stat.destination);
+ TR("Cancelling","%s",stat.cancelling>0 ? "YES" : "NO");
+ if (stat.cancelReason != NULL) {
+ TR("Cancel reason","%s",stat.cancelReason);
+ }
+ TR("CPU time","%d",stat.cpuTime);
+
+
+ TR("Done code","%d",stat.done_code);
+ TR("Exit code","%d",stat.exit_code);
+
+ if (stat.jdl) asprintf(&jdl,"<h3>Job description</h3>\r\n"
+ "<pre>%s</pre>\r\n",stat.jdl);
+
+ if (stat.rsl) asprintf(&rsl,"<h3>RSL</h3>\r\n"
+ "<pre>%s</pre>\r\n",stat.rsl);
+
+
+ asprintf(&pomA, "<html>\r\n\t<body>\r\n"
+ "<h2>%s</h2>\r\n"
+ "<table halign=\"left\">%s</table>"
+ "%s%s"
+ "\t</body>\r\n</html>",
+ chid,pomB,jdl,rsl);
+ free(pomB);
+
+ *message = pomA;
+
+ free(chid);
+ free(jdl);
+ free(rsl);
+ return 0;
+}
+
+char *edg_wll_ErrorToHTML(edg_wll_Context ctx,int code)
+{
+ char *out,*et,*ed;
+ char *msg = edg_wll_HTTPErrorMessage(code);
+ edg_wll_ErrorCode e;
+
+ e = edg_wll_Error(ctx,&et,&ed);
+ asprintf(&out,"<html><head><title>Error</title></head>\n"
+ "<body><h1>%s</h1>\n"
+ "%d: %s (%s)</body></html>",msg,e,et,ed);
+
+ free(et); free(ed);
+ return out;
+}
--- /dev/null
+#ifndef _LB_HTML
+#define _LB_HTML
+
+#ident "$Header$"
+
+#include "glite/lb/consumer.h"
+
+int edg_wll_QueryToHTML(edg_wll_Context,edg_wll_Event *,char **);
+int edg_wll_JobStatusToHTML(edg_wll_Context, edg_wll_JobStat, char **);
+int edg_wll_UserJobsToHTML(edg_wll_Context, edg_wlc_JobId *, char **);
+char *edg_wll_ErrorToHTML(edg_wll_Context,int);
+
+#endif
--- /dev/null
+#ident "$Header$"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <unistd.h>
+
+#include "glite/lb/consumer.h"
+#include "glite/lb/mini_http.h"
+#include "glite/lb/context-int.h"
+
+#include "lb_http.h"
+#include "lb_proto.h"
+
+#define dprintf(x) printf x
+
+
+int edg_wll_ServerHTTP(edg_wll_Context ctx)
+{
+ char **hdr = NULL,*req = NULL,*body = NULL,
+ **hdrOut = NULL, *resp = NULL, *bodyOut = NULL,
+ *err_desc = NULL;
+ edg_wll_ErrorCode err = 0;
+
+
+ err = edg_wll_http_recv(ctx,&req,&hdr,&body);
+
+ dprintf(("[%d] %s\n",getpid(),req));
+ if (body) dprintf(("\n%s\n\n",body));
+
+ if (!err) {
+ if ((err = edg_wll_Proto(ctx,req,hdr,body,&resp,&hdrOut,&bodyOut)))
+ edg_wll_Error(ctx,NULL,&err_desc);
+
+ if (resp) edg_wll_http_send(ctx,resp,(char const * const *)hdrOut,bodyOut);
+ }
+
+ free(req);
+ free(resp);
+ if (hdr) {
+ char **h;
+ for (h = hdr; *h; h++) free(*h);
+ free(hdr);
+ }
+ // hdrOut are static
+ free(body);
+ free(bodyOut);
+
+ if (err != edg_wll_Error(ctx,NULL,NULL)) edg_wll_SetError(ctx,err,err_desc);
+ free(err_desc);
+ return err;
+}
--- /dev/null
+#ifndef _LB_HTTP_H
+#define _LB_HTTP_H
+
+#ident "$Header$"
+
+#include <stdio.h>
+
+#include "glite/lb/consumer.h"
+
+int edg_wll_ServerHTTP(edg_wll_Context);
+
+#endif
--- /dev/null
+#ident "$Header$"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+#include <errno.h>
+
+#include <expat.h>
+
+#include "glite/lb/consumer.h"
+#include "glite/lb/context-int.h"
+#include "glite/lb/mini_http.h"
+#include "glite/lb/xml_conversions.h"
+#include "glite/lb/dump.h"
+#include "glite/lb/load.h"
+#include "glite/lb/purge.h"
+
+#include "lb_proto.h"
+#include "lb_html.h"
+#include "get_events.h"
+#include "purge.h"
+#include "lb_xml_parse.h"
+
+
+#define METHOD_GET "GET "
+#define METHOD_POST "POST "
+
+#define KEY_JOBS "/userJobs/"
+#define KEY_QUERY_JOBS "/queryJobs "
+#define KEY_QUERY_EVENTS "/queryEvents "
+#define KEY_PURGE_REQUEST "/purgeRequest "
+#define KEY_DUMP_REQUEST "/dumpRequest "
+#define KEY_LOAD_REQUEST "/loadRequest "
+#define KEY_INDEXED_ATTRS "/indexedAttrs "
+#define KEY_NOTIF_REQUEST "/notifRequest "
+#define KEY_HTTP "HTTP/1.1"
+
+
+#define KEY_ACCEPT "Accept:"
+#define KEY_APP "application/x-dglb"
+#define KEY_AGENT "User-Agent"
+
+
+const char* const response_headers[] = {
+ "Cache-Control: no-cache",
+ "Accept: application/x-dglb",
+ "User-Agent: edg_wll_Server/" PROTO_VERSION "/" COMP_PROTO,
+ "Content-Type: application/x-dglb",
+ NULL
+};
+
+extern int edg_wll_NotifNewServer(edg_wll_Context,
+ edg_wll_QueryRec const * const *, char const *,
+ const edg_wll_NotifId, time_t *);
+extern int edg_wll_NotifBindServer(edg_wll_Context,
+ const edg_wll_NotifId, const char *, time_t *);
+extern int edg_wll_NotifChangeServer(edg_wll_Context,
+ const edg_wll_NotifId, edg_wll_QueryRec const * const *,
+ edg_wll_NotifChangeOp);
+extern int edg_wll_NotifRefreshServer(edg_wll_Context,
+ const edg_wll_NotifId, time_t *);
+extern int edg_wll_NotifDropServer(edg_wll_Context, edg_wll_NotifId *);
+
+
+
+char *edg_wll_HTTPErrorMessage(int errCode)
+{
+ char *msg;
+
+ switch (errCode) {
+ case HTTP_OK: msg = "OK"; break;
+ case HTTP_BADREQ: msg = "Bad Request"; break;
+ case HTTP_UNAUTH: msg = "Unauthorized"; break;
+ case HTTP_NOTFOUND: msg = "Not Found"; break;
+ case HTTP_NOTALLOWED: msg = "Method Not Allowed"; break;
+ case HTTP_UNSUPPORTED: msg = "Unsupported Media Type"; break;
+ case HTTP_NOTIMPL: msg = "Not Implemented"; break;
+ case HTTP_INTERNAL: msg = "Internal Server Error"; break;
+ case HTTP_UNAVAIL: msg = "Service Unavailable"; break;
+ case HTTP_INVALID: msg = "Invalid Data"; break;
+ default: msg = "Unknown error"; break;
+ }
+
+ return msg;
+}
+
+/* returns non-zero if protocols incompatible */
+static int is_protocol_incompatible(char *user_agent)
+{
+ char *version, *comp_proto, *needle;
+ double v, c, my_v = strtod(PROTO_VERSION, (char **) NULL), my_c;
+
+
+ /* get version od the other side */
+ if ((version = strstr(user_agent,"/")) == NULL) return(-1);
+ else v = strtod(++version, &needle);
+
+ /* sent the other side list of compatible protocols? */
+ if ( needle[0] == '\0' ) return(-2);
+
+ /* test compatibility if server newer*/
+ if (my_v > v) {
+ comp_proto=COMP_PROTO;
+ do {
+ my_c = strtod(comp_proto, &needle);
+ if (my_c == v) return(0);
+ comp_proto = needle + 1;
+ } while (needle[0] != '\0');
+ return(1);
+ }
+
+ /* test compatibility if server is older */
+ else if (my_v < v) {
+ do {
+ comp_proto = needle + 1;
+ c = strtod(comp_proto, &needle);
+ if (my_v == c) return(0);
+ } while (needle[0] != '\0');
+ return(1);
+ }
+
+ /* version match */
+ return(0);
+}
+
+
+static int outputHTML(char **headers)
+{
+ int i;
+
+ if (!headers) return 0;
+
+ for (i=0; headers[i]; i++)
+ if (!strncmp(headers[i], KEY_ACCEPT, sizeof(KEY_ACCEPT) - 1)) {
+ if (strstr(headers[i],KEY_APP))
+ return 0; /* message sent by edg_wll_Api */
+ else
+ return 1; /* message sent by other application */
+ }
+ return 1;
+
+}
+
+
+
+edg_wll_ErrorCode edg_wll_Proto(edg_wll_Context ctx,
+ char *request,char **headers,char *messageBody,
+ char **response,char ***headersOut,char **bodyOut)
+{
+ //char *requestPTR, *pom, *message = NULL; Ely 16/10 unused variable `pom'
+ char *requestPTR, *message = NULL;
+ int ret = HTTP_OK;
+ int html = outputHTML(headers);
+ int i;
+
+ edg_wll_ResetError(ctx);
+
+ for (i=0; headers[i]; i++) /* find line with version number in headers */
+ if ( strstr(headers[i], KEY_AGENT) ) break;
+
+ if (headers[i] == NULL) { ret = HTTP_BADREQ; goto err; } /* if not present */
+ switch (is_protocol_incompatible(headers[i])) {
+ case 0 : /* protocols compatible */
+ break;
+ case -1 : /* malformed 'User Agent:' line */
+ ret = HTTP_BADREQ;
+ goto err;
+ break;
+ case -2 : /* version of one protocol unknown */
+ /* fallthrough */
+ case 1 : /* protocols incompatible */
+ /* fallthrough */
+ default : ret = HTTP_UNSUPPORTED;
+ edg_wll_SetError(ctx,ENOTSUP,"Protocol versions are incompatible.");
+ goto err;
+ break;
+ }
+
+
+/* GET */
+ if (!strncmp(request, METHOD_GET, sizeof(METHOD_GET)-1)) {
+
+ requestPTR = request + sizeof(METHOD_GET)-1;
+
+
+ /* GET /: Current User Jobs */
+ if (requestPTR[0]=='/' && (requestPTR[1]==' ' || requestPTR[1]=='?')) {
+ edg_wlc_JobId *jobsOut = NULL;
+ int i, flags;
+
+ flags = (requestPTR[1]=='?') ? edg_wll_string_to_stat_flags(requestPTR + 2) : 0;
+
+// FIXME: edg_wll_UserJobs should take flags as parameter
+ if (!ctx->peerName) {
+ edg_wll_SetError(ctx,EPERM,"Operation not permitted.");
+ ret = HTTP_UNAUTH;
+ }
+ switch (edg_wll_UserJobs(ctx,&jobsOut,NULL)) {
+ case 0: if (html) edg_wll_UserJobsToHTML(ctx, jobsOut, &message);
+ else ret = HTTP_OK;
+ break;
+ case ENOENT: ret = HTTP_NOTFOUND; break;
+ default: ret = HTTP_INTERNAL; break;
+ }
+ if (!html && (ret != HTTP_INTERNAL))
+ if (edg_wll_UserJobsToXML(ctx, jobsOut, &message))
+ ret = HTTP_INTERNAL;
+
+ if (jobsOut) {
+ for (i=0; jobsOut[i]; i++) edg_wlc_JobIdFree(jobsOut[i]);
+ free(jobsOut);
+ }
+ }
+
+ /* GET /[jobId]: Job Status */
+ else if (*requestPTR=='/') {
+ edg_wlc_JobId jobId = NULL;
+ char *pom1,*fullid = NULL;
+ edg_wll_JobStat stat;
+ char *pomCopy;
+
+ if (ctx->srvName == NULL) {
+ edg_wll_SetError(ctx, EDG_WLL_ERROR_SERVER_RESPONSE,
+ "no server name on GET /jobid");
+ ret = HTTP_INTERNAL;
+ goto err;
+ }
+ memset(&stat,0,sizeof(stat));
+ pomCopy = strdup(requestPTR + 1);
+ for (pom1=pomCopy; *pom1 && !isspace(*pom1); pom1++);
+ *pom1 = 0;
+
+ asprintf(&fullid,GLITE_WMSC_JOBID_PROTO_PREFIX"%s:%u/%s",ctx->srvName,ctx->srvPort,pomCopy);
+ free(pomCopy);
+
+ if (edg_wlc_JobIdParse(fullid, &jobId)) {
+ edg_wll_SetError(ctx,EDG_WLL_ERROR_JOBID_FORMAT,fullid);
+ ret = HTTP_BADREQ;
+ }
+ else switch (edg_wll_JobStatus(ctx,jobId,0,&stat)) {
+ case 0: if (html) edg_wll_JobStatusToHTML(ctx,stat,&message);
+ else ret = HTTP_OK;
+ break;
+ case ENOENT: ret = HTTP_NOTFOUND; break;
+ case EINVAL: ret = HTTP_INVALID; break;
+ case EPERM : ret = HTTP_UNAUTH; break;
+ default: ret = HTTP_INTERNAL; break;
+ }
+ if (!html && (ret != HTTP_INTERNAL))
+ if (edg_wll_JobStatusToXML(ctx,stat,&message))
+ ret = HTTP_INTERNAL;
+
+ free(fullid);
+ edg_wlc_JobIdFree(jobId);
+ edg_wll_FreeStatus(&stat);
+
+ /* GET [something else]: not understood */
+ } else ret = HTTP_BADREQ;
+
+/* POST */
+ } else if (!strncmp(request,METHOD_POST,sizeof(METHOD_POST)-1)) {
+
+ requestPTR = request + sizeof(METHOD_POST)-1;
+
+ if (!strncmp(requestPTR,KEY_QUERY_EVENTS,sizeof(KEY_QUERY_EVENTS)-1)) {
+ edg_wll_Event *eventsOut = NULL;
+ edg_wll_QueryRec **job_conditions = NULL, **event_conditions = NULL;
+ int i,j;
+
+ if (parseQueryEventsRequest(ctx, messageBody, &job_conditions, &event_conditions))
+ ret = HTTP_BADREQ;
+
+ else {
+ int fatal = 0;
+
+ switch (edg_wll_QueryEventsServer(ctx,ctx->noAuth,
+ (const edg_wll_QueryRec **)job_conditions,
+ (const edg_wll_QueryRec **)event_conditions, &eventsOut)) {
+
+ case 0: if (html) ret = HTTP_NOTIMPL;
+ else ret = HTTP_OK;
+ break;
+ case ENOENT: ret = HTTP_NOTFOUND; break;
+ case EPERM : ret = HTTP_UNAUTH; break;
+ case E2BIG: ret = HTTP_UNAUTH; break;
+ case EINVAL: ret = HTTP_UNAUTH; break;
+ case EDG_WLL_ERROR_NOINDEX: ret = HTTP_UNAUTH; break;
+ case ENOMEM: fatal = 1; ret = HTTP_INTERNAL; break;
+ default: ret = HTTP_INTERNAL; break;
+ }
+ /* glue errors (if eny) to XML responce */
+ if (!html && !fatal)
+ if (edg_wll_QueryEventsToXML(ctx, eventsOut, &message))
+ ret = HTTP_INTERNAL;
+ }
+
+ if (job_conditions) {
+ for (j = 0; job_conditions[j]; j++) {
+ for (i = 0 ; (job_conditions[j][i].attr != EDG_WLL_QUERY_ATTR_UNDEF); i++ )
+ edg_wll_QueryRecFree(&job_conditions[j][i]);
+ free(job_conditions[j]);
+ }
+ free(job_conditions);
+ }
+
+ if (event_conditions) {
+ for (j = 0; event_conditions[j]; j++) {
+ for (i = 0 ; (event_conditions[j][i].attr != EDG_WLL_QUERY_ATTR_UNDEF); i++ )
+ edg_wll_QueryRecFree(&event_conditions[j][i]);
+ free(event_conditions[j]);
+ }
+ free(event_conditions);
+ }
+
+ if (eventsOut != NULL) {
+ for (i=0; eventsOut[i].type != EDG_WLL_EVENT_UNDEF; i++)
+ edg_wll_FreeEvent(&(eventsOut[i]));
+ edg_wll_FreeEvent(&(eventsOut[i])); /* free last line */
+ free(eventsOut);
+ }
+ }
+ else if (!strncmp(requestPTR,KEY_QUERY_JOBS,sizeof(KEY_QUERY_JOBS)-1)) {
+ edg_wlc_JobId *jobsOut = NULL;
+ edg_wll_JobStat *statesOut = NULL;
+ edg_wll_QueryRec **conditions = NULL;
+ int i,j, flags = 0;
+
+ if (parseQueryJobsRequest(ctx, messageBody, &conditions, &flags))
+ ret = HTTP_BADREQ;
+
+ else {
+ int fatal = 0,
+ retCode;
+
+ if (flags & EDG_WLL_STAT_NO_JOBS) {
+ flags -= EDG_WLL_STAT_NO_JOBS;
+ jobsOut = NULL;
+ if (flags & EDG_WLL_STAT_NO_STATES) {
+ flags -= EDG_WLL_STAT_NO_STATES;
+ statesOut = NULL;
+ retCode = edg_wll_QueryJobsServer(ctx, (const edg_wll_QueryRec **)conditions, flags, NULL, NULL);
+ }
+ else
+ retCode = edg_wll_QueryJobsServer(ctx, (const edg_wll_QueryRec **)conditions, flags, NULL, &statesOut);
+ }
+ else {
+ if (flags & EDG_WLL_STAT_NO_STATES) {
+ flags -= EDG_WLL_STAT_NO_STATES;
+ statesOut = NULL;
+ retCode = edg_wll_QueryJobsServer(ctx, (const edg_wll_QueryRec **)conditions, flags, &jobsOut, NULL);
+ }
+ else
+ retCode = edg_wll_QueryJobsServer(ctx, (const edg_wll_QueryRec **)conditions, flags, &jobsOut, &statesOut);
+ }
+
+ switch ( retCode ) {
+ // case EPERM : ret = HTTP_UNAUTH;
+ // /* soft-error fall through */
+ case 0: if (html) ret = HTTP_NOTIMPL;
+ else ret = HTTP_OK;
+
+ break;
+ case ENOENT: ret = HTTP_NOTFOUND; break;
+ case EPERM: ret = HTTP_UNAUTH; break;
+ case E2BIG: ret = HTTP_UNAUTH; break;
+ case EINVAL: ret = HTTP_UNAUTH; break;
+ case EDG_WLL_ERROR_NOINDEX: ret = HTTP_UNAUTH; break;
+ case ENOMEM: fatal = 1; ret = HTTP_INTERNAL; break;
+ default: ret = HTTP_INTERNAL; break;
+ }
+ if (!html && !fatal)
+ if (edg_wll_QueryJobsToXML(ctx, jobsOut, statesOut, &message))
+ ret = HTTP_INTERNAL;
+ }
+
+ if (conditions) {
+ for (j = 0; conditions[j]; j++) {
+ for (i = 0; (conditions[j][i].attr != EDG_WLL_QUERY_ATTR_UNDEF); i++ )
+ edg_wll_QueryRecFree(&conditions[j][i]);
+ free(conditions[j]);
+ }
+ free(conditions);
+ }
+
+ if (jobsOut) {
+ for (i=0; jobsOut[i]; i++) edg_wlc_JobIdFree(jobsOut[i]);
+ free(jobsOut);
+ }
+ if (statesOut) {
+ for (i=0; statesOut[i].state != EDG_WLL_JOB_UNDEF; i++)
+ edg_wll_FreeStatus(&(statesOut[i]));
+ edg_wll_FreeStatus(&(statesOut[i])); /* free last line */
+ free(statesOut);
+ }
+ }
+ else if (!strncmp(requestPTR,KEY_PURGE_REQUEST,sizeof(KEY_PURGE_REQUEST)-1)) {
+ edg_wll_PurgeRequest request;
+
+ if ( !parsePurgeRequest(ctx,messageBody,(int (*)()) edg_wll_StringToStat,&request) )
+ edg_wll_PurgeServer(ctx, (const edg_wll_PurgeRequest *)&request);
+
+ if ( request.jobs )
+ {
+ int i;
+ for ( i = 0; request.jobs[i]; i++ )
+ free(request.jobs[i]);
+ free(request.jobs);
+ }
+
+ /*
+ * response allready sent from edg_wll_PurgeServer() - return NULL results
+ */
+ *response = NULL;
+ *headersOut = NULL;
+ *bodyOut = NULL;
+ return edg_wll_Error(ctx,NULL,NULL);
+ }
+ else if (!strncmp(requestPTR,KEY_DUMP_REQUEST,sizeof(KEY_DUMP_REQUEST)-1)) {
+ edg_wll_DumpRequest request;
+ edg_wll_DumpResult result;
+
+ memset(&request,0,sizeof(request));
+ memset(&result,0,sizeof(result));
+
+ if (parseDumpRequest(ctx, messageBody, &request))
+ ret = HTTP_BADREQ;
+ else {
+ int fatal = 0;
+
+ switch (edg_wll_DumpEvents(ctx,(const edg_wll_DumpRequest *) &request, &result)) {
+ case 0: if (html) ret = HTTP_NOTIMPL;
+ else ret = HTTP_OK;
+ break;
+ case ENOENT: ret = HTTP_NOTFOUND; break;
+ case EPERM : ret = HTTP_UNAUTH; break;
+ case EDG_WLL_ERROR_NOINDEX: ret = HTTP_UNAUTH; break;
+ case ENOMEM: fatal = 1; ret = HTTP_INTERNAL; break;
+ default: ret = HTTP_INTERNAL; break;
+ }
+ /* glue errors (if eny) to XML responce */
+ if (!html && !fatal)
+ if (edg_wll_DumpResultToXML(ctx, &result, &message))
+ ret = HTTP_INTERNAL;
+ }
+
+ free(result.server_file);
+ }
+ else if (!strncmp(requestPTR,KEY_LOAD_REQUEST,sizeof(KEY_LOAD_REQUEST)-1)) {
+ edg_wll_LoadRequest request;
+ edg_wll_LoadResult result;
+
+ memset(&request,0,sizeof(request));
+ memset(&result,0,sizeof(result));
+
+ if (parseLoadRequest(ctx, messageBody, &request))
+ ret = HTTP_BADREQ;
+ else {
+ int fatal = 0;
+
+ switch (edg_wll_LoadEvents(ctx,(const edg_wll_LoadRequest *) &request, &result)) {
+ case 0: if (html) ret = HTTP_NOTIMPL;
+ else ret = HTTP_OK;
+ break;
+ case EEXIST: ret = HTTP_OK; break;
+ case EINVAL: ret = HTTP_INVALID; break;
+ case ENOENT: ret = HTTP_NOTFOUND; break;
+ case EPERM : ret = HTTP_UNAUTH; break;
+ case EDG_WLL_ERROR_NOINDEX: ret = HTTP_UNAUTH; break;
+ case ENOMEM: fatal = 1; ret = HTTP_INTERNAL; break;
+ default: ret = HTTP_INTERNAL; break;
+ }
+ /* glue errors (if eny) to XML responce */
+ if (!html && !fatal)
+ if (edg_wll_LoadResultToXML(ctx, &result, &message))
+ ret = HTTP_INTERNAL;
+ }
+
+ free(result.server_file);
+ }
+ else if (!strncmp(requestPTR,KEY_INDEXED_ATTRS,sizeof(KEY_INDEXED_ATTRS)-1)) {
+ if (!html)
+ if (edg_wll_IndexedAttrsToXML(ctx, &message))
+ ret = HTTP_INTERNAL;
+ }
+ else if (!strncmp(requestPTR,KEY_NOTIF_REQUEST,sizeof(KEY_NOTIF_REQUEST)-1)) {
+ char *function, *address;
+ edg_wll_NotifId notifId;
+ edg_wll_NotifChangeOp op;
+ edg_wll_QueryRec **conditions;
+ time_t validity = -1;
+ int i,j;
+
+
+ if (parseNotifRequest(ctx, messageBody, &function, ¬ifId,
+ &address, &op, &conditions))
+ ret = HTTP_BADREQ;
+ else {
+ int fatal = 0, err = 0;
+
+ // XXX presne poradi parametru zatim neni znamo
+ // navratove chyby nejsou zname, nutno predelat dle aktualni situace
+ if (!strcmp(function,"New"))
+ err = edg_wll_NotifNewServer(ctx,
+ (edg_wll_QueryRec const * const *)conditions,
+ address, notifId, &validity);
+ else if (!strcmp(function,"Bind"))
+ err = edg_wll_NotifBindServer(ctx, notifId, address, &validity);
+ else if (!strcmp(function,"Change"))
+ err = edg_wll_NotifChangeServer(ctx, notifId,
+ (edg_wll_QueryRec const * const *)conditions, op);
+ else if (!strcmp(function,"Refresh"))
+ err = edg_wll_NotifRefreshServer(ctx, notifId, &validity);
+ else if (!strcmp(function,"Drop"))
+ err = edg_wll_NotifDropServer(ctx, notifId);
+
+ switch (err) {
+ case 0: if (html) ret = HTTP_NOTIMPL;
+ else ret = HTTP_OK;
+ break;
+ case EEXIST: ret = HTTP_OK; break;
+ case EINVAL: ret = HTTP_INVALID; break;
+ case ENOENT: ret = HTTP_NOTFOUND; break;
+ case EPERM : ret = HTTP_UNAUTH; break;
+ case EDG_WLL_ERROR_NOINDEX: ret = HTTP_UNAUTH; break;
+ case ENOMEM: fatal = 1; ret = HTTP_INTERNAL; break;
+ default: ret = HTTP_INTERNAL; break;
+ }
+ /* glue errors (if eny) to XML responce */
+ if (!html && !fatal)
+ if (edg_wll_NotifResultToXML(ctx, validity, &message))
+ ret = HTTP_INTERNAL;
+ }
+
+ free(function);
+ free(address);
+ edg_wll_NotifIdFree(notifId);
+ if (conditions) {
+ for (j = 0; conditions[j]; j++) {
+ for (i = 0; (conditions[j][i].attr != EDG_WLL_QUERY_ATTR_UNDEF); i++ )
+ edg_wll_QueryRecFree(&conditions[j][i]);
+ free(conditions[j]);
+ }
+ free(conditions);
+ }
+ }
+
+ /* POST [something else]: not understood */
+ else ret = HTTP_BADREQ;
+
+/* other HTTP methods */
+ } else ret = HTTP_NOTALLOWED;
+
+err: asprintf(response,"HTTP/1.1 %d %s",ret,edg_wll_HTTPErrorMessage(ret));
+ //(*headersOut) = malloc(2*sizeof(**headersOut));
+ //(*headersOut)[0] = strdup("Cache-Control: no-cache");
+ //(*headersOut)[1] = NULL;
+ *headersOut = (char **) response_headers;
+ if ((ret != HTTP_OK) && html)
+ *bodyOut = edg_wll_ErrorToHTML(ctx,ret);
+ else
+ *bodyOut = message;
+
+ return edg_wll_Error(ctx,NULL,NULL);
+}
--- /dev/null
+#ifndef _LB_PROTO_H
+#define _LB_PROTO_H
+
+#ident "$Header$"
+
+#include "glite/lb/consumer.h"
+
+extern const char* const response_headers[];
+
+/* Handle a single request of the LB server protocol
+ * returns a complete response string (may contain a formatted error
+ * message)
+ * or NULL on fatal error*/
+
+extern edg_wll_ErrorCode edg_wll_Proto(
+ edg_wll_Context, /* INOUT: context */
+ char *, /* IN: HTTP request line */
+ char **, /* IN: HTTP message headers */
+ char *, /* IN: HTTP message body */
+ char **, /* OUT: HTTP response line */
+ char ***, /* OUT: HTTP response headers */
+ char ** /* OUT: HTTP response body */
+);
+
+extern char *edg_wll_HTTPErrorMessage(int);
+
+#endif
--- /dev/null
+#ident "$Header$"
+
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <ctype.h>
+#include <expat.h>
+
+#include "glite/wms/jobid/cjobid.h"
+
+#include "glite/lb/consumer.h"
+#include "glite/lb/escape.h"
+#include "glite/lb/context-int.h"
+#include "glite/lb/trio.h"
+#include "glite/lb/xml_conversions.h"
+
+#include "glite/lb/purge.h"
+#include "glite/lb/dump.h"
+#include "glite/lb/load.h"
+
+#include "lb_xml_parse.h"
+
+#ifdef __GNUC__
+#define UNUSED_VAR __attribute__((unused))
+#else
+#define UNUSED_VAR
+#endif
+
+#define QUERY_EVENTS_BEGIN "<edg_wll_QueryEventsResult"
+#define QUERY_EVENTS_END "</edg_wll_QueryEventsResult>\r\n"
+#define QUERY_JOBS_BEGIN "<edg_wll_QueryJobsResult"
+#define QUERY_JOBS_END "</edg_wll_QueryJobsResult>\r\n"
+#define PURGE_RESULT_BEGIN "<edg_wll_PurgeResult"
+#define PURGE_RESULT_END "</edg_wll_PurgeResult>\r\n"
+#define DUMP_RESULT_BEGIN "<edg_wll_DumpResult"
+#define DUMP_RESULT_END "</edg_wll_DumpResult>\r\n"
+#define LOAD_RESULT_BEGIN "<edg_wll_LoadResult"
+#define LOAD_RESULT_END "</edg_wll_LoadResult>\r\n"
+#define INDEXED_ATTRS_BEGIN "<edg_wll_GetIndexedAttributesResult"
+#define INDEXED_ATTRS_END "</edg_wll_GetIndexedAttributesResult>\r\n"
+#define NOTIF_RESULT_BEGIN "<edg_wll_NotifResult"
+#define NOTIF_RESULT_END "</edg_wll_NotifResult>\r\n"
+
+
+
+// XXX will be redundant soon
+#define USERJOBS_BEGIN "<edg_wll_UserJobs"
+#define USERJOBS_END "</edg_wll_UserJobs>\r\n"
+
+
+static char *ops[] = { "equal","less","greater","within","unequal" },
+ *attrs[] = { "jobid","owner","status","location","destination",
+ "donecode","usertag","time","level","host","source",
+ "instance","type","chkpt_tag", "resubmitted", "parent_job", "exitcode" };
+
+static const struct timeval null_timeval = {0,0};
+
+#define unexp() {\
+ char *e;\
+\
+ if (XMLCtx->errtxt) {\
+ asprintf(&e,"%s\nunexpected <%s> at line %d",XMLCtx->errtxt,\
+ el,XML_GetCurrentLineNumber(XMLCtx->p));\
+ free(XMLCtx->errtxt);\
+ } else asprintf(&e,"unexpected <%s> at line %d",\
+ el,XML_GetCurrentLineNumber(XMLCtx->p));\
+ XMLCtx->errtxt = e;\
+}
+
+
+
+static void startJobQueryRec(void *data, const char *el, const char **attr)
+{
+ unsigned int i;
+ edg_wll_XML_ctx *XMLCtx = data;
+
+
+ strcpy(XMLCtx->element, el);
+
+ switch (XMLCtx->level) {
+ case 0: if (strcasecmp(el,"and")) unexp()
+ break;
+ case 1: if (strcasecmp(el,"orJobConditions")) unexp()
+ else {
+ XMLCtx->position = -1;
+ XMLCtx->job_conditions = realloc(XMLCtx->job_conditions,
+ (++XMLCtx->row+2)*sizeof(*XMLCtx->job_conditions));
+ XMLCtx->job_conditions[XMLCtx->row] = NULL;
+ XMLCtx->job_conditions[XMLCtx->row+1] = NULL;
+ }
+ break;
+ case 2:
+ for (i=0; i<sizeof(ops)/sizeof(ops[0]); i++)
+ if (!strcasecmp(el,ops[i])) break;
+ if (i == sizeof(ops)/sizeof(ops[0])) unexp()
+ else {
+ if (!XMLCtx->job_conditions) break;
+
+ /* malloc also terminator and set it to 0 (= EDG_WLL_QUERY_ATTR_UNDEF) */
+ XMLCtx->job_conditions[XMLCtx->row] = realloc(XMLCtx->job_conditions[XMLCtx->row],
+ (++XMLCtx->position+2)*sizeof(**XMLCtx->job_conditions));
+ memset(&XMLCtx->job_conditions[XMLCtx->row][XMLCtx->position],0,2*sizeof(**XMLCtx->job_conditions));
+ XMLCtx->job_conditions[XMLCtx->row][XMLCtx->position].op = i;
+ XMLCtx->bound = 0;
+ }
+ break;
+ case 3: for (i=0; i<sizeof(attrs)/sizeof(attrs[0]) &&
+ strcasecmp(el,attrs[i]); i++);
+ if (i == sizeof(attrs)/sizeof(attrs[0])) unexp()
+ else {
+ if (!XMLCtx->job_conditions) break;
+ if (!XMLCtx->job_conditions[XMLCtx->row]) break;
+
+ if ( (i+1) == EDG_WLL_QUERY_ATTR_USERTAG) {
+ if (!attr[0] || !attr[1]) { unexp() break;}
+ if (strcmp(attr[0],"name")) { unexp() break;}
+ XMLCtx->job_conditions[XMLCtx->row][XMLCtx->position].attr_id.tag = strdup(attr[1]);
+ }
+ else if ( (i+1) == EDG_WLL_QUERY_ATTR_TIME) {
+ if (!attr[0] || !attr[1]) { unexp() break;}
+ if (attr[0] && strcmp(attr[0],"state")) { unexp() break;}
+ XMLCtx->job_conditions[XMLCtx->row][XMLCtx->position].attr_id.state = edg_wll_StringToStat(attr[1]);
+ }
+ XMLCtx->job_conditions[XMLCtx->row][XMLCtx->position].attr = i+1;
+ }
+ break;
+ default: unexp(); break;
+ }
+ XMLCtx->level++;
+}
+
+
+
+static void startQueryJobsRequest(void *data, const char *el, const char **attr)
+{
+ unsigned int i;
+ edg_wll_XML_ctx *XMLCtx = data;
+
+
+ strcpy(XMLCtx->element, el);
+
+ switch (XMLCtx->level) {
+ case 0: if (strcasecmp(el,"edg_wll_QueryJobsRequest")) { unexp() break; }
+ for ( i = 0; attr[i] && attr[i+1]; i += 2 )
+ {
+ if ( !strcmp(attr[i],"softLimit") )
+ XMLCtx->ctx->softLimit = atoi(attr[i+1]);
+ else if ( !strcmp(attr[i],"queryRes") )
+ XMLCtx->ctx->p_query_results = atoi(attr[i+1]);
+ else { unexp() break; }
+ }
+ break;
+ case 1: if (!strcasecmp(el,"and")) {
+ XMLCtx->jobQueryRec_begin = XML_GetCurrentByteIndex(XMLCtx->p);
+ break;
+ }
+ else if (!strcasecmp(el,"flags")) break;
+ else unexp()
+ break;
+ case 2: /* fall through */
+ case 3: /* do not check xml tags, processed in startJobQueryRec */
+ case 4: break;
+ default: unexp(); break;
+ }
+ XMLCtx->level++;
+}
+
+
+static void startQueryEventsRequest(void *data, const char *el, const char **attr UNUSED_VAR)
+{
+ unsigned int i;
+ edg_wll_XML_ctx *XMLCtx = data;
+
+
+ strcpy(XMLCtx->element, el);
+
+ switch (XMLCtx->level) {
+ case 0: if (strcasecmp(el,"edg_wll_QueryEventsRequest")) { unexp() break; }
+ for ( i = 0; attr[i] && attr[i+1]; i += 2 )
+ {
+ if ( !strcmp(attr[i],"softLimit") )
+ XMLCtx->ctx->softLimit = atoi(attr[i+1]);
+ else if ( !strcmp(attr[i],"queryRes") )
+ XMLCtx->ctx->p_query_results = atoi(attr[i+1]);
+ else { unexp() break; }
+ }
+ break;
+ case 1: if (strcasecmp(el,"and")) unexp()
+ break;
+ case 2: if (!strcasecmp(el,"orJobConditions")) {
+ XMLCtx->type = EDG_WLL_QUERY_TYPE_JOB_CONDITION;
+ XMLCtx->position = -1;
+ XMLCtx->job_conditions = realloc(XMLCtx->job_conditions,
+ (++XMLCtx->row+2)*sizeof(*XMLCtx->job_conditions));
+ XMLCtx->job_conditions[XMLCtx->row] = NULL;
+ XMLCtx->job_conditions[XMLCtx->row+1] = NULL;
+
+ }
+ else if (!strcasecmp(el,"orEventConditions")) {
+ XMLCtx->type = EDG_WLL_QUERY_TYPE_EVENT_CONDITION;
+ XMLCtx->position2 = -1;
+ XMLCtx->event_conditions = realloc(XMLCtx->event_conditions,
+ (++XMLCtx->row2+2)*sizeof(*XMLCtx->event_conditions));
+ XMLCtx->event_conditions[XMLCtx->row2] = NULL;
+ XMLCtx->event_conditions[XMLCtx->row2+1] = NULL;
+ }
+ else unexp()
+ break;
+ case 3:
+ for (i=0; i<sizeof(ops)/sizeof(ops[0]); i++)
+ if (!strcasecmp(el,ops[i])) break;
+ if (i == sizeof(ops)/sizeof(ops[0])) unexp()
+ else if (XMLCtx->type == EDG_WLL_QUERY_TYPE_JOB_CONDITION) {
+ if (!XMLCtx->job_conditions) break;
+
+ /* malloc also terminator and set it to 0 (= EDG_WLL_QUERY_ATTR_UNDEF) */
+ XMLCtx->job_conditions[XMLCtx->row] = realloc(XMLCtx->job_conditions[XMLCtx->row],
+ (++XMLCtx->position+2)*sizeof(**XMLCtx->job_conditions));
+ memset(&XMLCtx->job_conditions[XMLCtx->row][XMLCtx->position],0,2*sizeof(**XMLCtx->job_conditions));
+ XMLCtx->job_conditions[XMLCtx->row][XMLCtx->position].op = i;
+ XMLCtx->bound = 0;
+ }
+ else if (XMLCtx->type == EDG_WLL_QUERY_TYPE_EVENT_CONDITION) {
+ if (!XMLCtx->event_conditions) break;
+ /* malloc also terminator and set it to 0 (= EDG_WLL_QUERY_ATTR_UNDEF) */
+ XMLCtx->event_conditions[XMLCtx->row2] = realloc(XMLCtx->event_conditions[XMLCtx->row2],
+ (++XMLCtx->position2+2)*sizeof(**XMLCtx->event_conditions));
+ memset(&XMLCtx->event_conditions[XMLCtx->row2][XMLCtx->position2],0,2*sizeof(**XMLCtx->event_conditions));
+ XMLCtx->event_conditions[XMLCtx->row2][XMLCtx->position2].op = i;
+ XMLCtx->bound = 0;
+ }
+
+ break;
+ case 4: for (i=0; i<sizeof(attrs)/sizeof(attrs[0]) &&
+ strcasecmp(el,attrs[i]); i++);
+ if (i == sizeof(attrs)/sizeof(attrs[0])) unexp()
+ else if (XMLCtx->type == EDG_WLL_QUERY_TYPE_JOB_CONDITION) {
+ if (!XMLCtx->job_conditions[XMLCtx->row]) break;
+ if ( (i+1) == EDG_WLL_QUERY_ATTR_USERTAG) {
+ if (!attr[0] || !attr[1]) { unexp() break;}
+ if (attr[0] && strcmp(attr[0],"name")) { unexp() break;}
+ XMLCtx->job_conditions[XMLCtx->row][XMLCtx->position].attr_id.tag = strdup(attr[1]);
+ }
+ else if ( (i+1) == EDG_WLL_QUERY_ATTR_TIME) {
+ if (!attr[0] || !attr[1]) { unexp() break;}
+ if (attr[0] && strcmp(attr[0],"state")) { unexp() break;}
+ XMLCtx->job_conditions[XMLCtx->row][XMLCtx->position].attr_id.state = edg_wll_StringToStat(attr[1]);
+ printf("\nchecking time attr\n%s = %s (%d)\n\n", attr[0], attr[1], edg_wll_StringToStat(attr[1]));
+ }
+ XMLCtx->job_conditions[XMLCtx->row][XMLCtx->position].attr = i+1;
+ }
+ else if (XMLCtx->type == EDG_WLL_QUERY_TYPE_EVENT_CONDITION) {
+ if (!XMLCtx->event_conditions[XMLCtx->row2]) break;
+ if ( (i+1) == EDG_WLL_QUERY_ATTR_USERTAG) {
+ if (!attr[0] || !attr[1]) { unexp() break;}
+ if (attr[0] && strcmp(attr[0],"name")) { unexp() break;}
+ XMLCtx->event_conditions[XMLCtx->row2][XMLCtx->position].attr_id.tag = strdup(attr[1]);
+ }
+ else if ( (i+1) == EDG_WLL_QUERY_ATTR_TIME) {
+ if (!attr[0] || !attr[1]) { unexp() break;}
+ if (attr[0] && strcmp(attr[0],"state")) { unexp() break;}
+ XMLCtx->event_conditions[XMLCtx->row2][XMLCtx->position].attr_id.state = edg_wll_StringToStat(attr[1]);
+ }
+ XMLCtx->event_conditions[XMLCtx->row2][XMLCtx->position2].attr = i+1;
+ }
+ break;
+ default: unexp(); break;
+ }
+ XMLCtx->level++;
+}
+
+
+
+static void startPurgeRequest(void *data, const char *el, const char **attr)
+{
+ edg_wll_XML_ctx *XMLCtx = data;
+
+
+ strcpy(XMLCtx->element, el);
+
+ switch (XMLCtx->level) {
+ case 0: if (strcasecmp(el,"edg_wll_PurgeRequest")) unexp()
+ break;
+ case 1: if (strcasecmp(el,"jobs") && strcasecmp(el,"timeout")
+ && strcasecmp(el,"flags")) unexp()
+ else
+ XMLCtx->position = 0;
+ break;
+ case 2: if (!strcasecmp(el,"jobId")) {
+ XMLCtx->purgeRequestGlobal.jobs = realloc(XMLCtx->purgeRequestGlobal.jobs,
+ (XMLCtx->position+2) * sizeof(XMLCtx->purgeRequestGlobal.jobs));
+
+ if (!XMLCtx->purgeRequestGlobal.jobs) {
+ edg_wll_SetError(XMLCtx->ctx, ENOMEM, NULL);
+ unexp() return;
+ }
+ XMLCtx->purgeRequestGlobal.jobs[XMLCtx->position+1] = NULL;
+ }
+ else if (XMLCtx->tagToIndex(el) >= 0 ) {
+ /* static array, no need to initialize & allocate anything */
+ }
+ else
+ unexp()
+ break;
+ default: unexp()
+ break;
+ }
+ XMLCtx->level++;
+}
+
+
+static void startDumpRequest(void *data, const char *el, const char **attr)
+{
+ edg_wll_XML_ctx *XMLCtx = data;
+
+
+ strcpy(XMLCtx->element, el);
+
+ switch (XMLCtx->level) {
+ case 0: if (strcasecmp(el,"edg_wll_DumpRequest")) unexp()
+ break;
+ case 1: if (strcasecmp(el,"from") && strcasecmp(el,"to")) unexp()
+ break;
+ default: unexp()
+ break;
+ }
+ XMLCtx->level++;
+}
+
+
+
+static void startLoadRequest(void *data, const char *el, const char **attr)
+{
+ edg_wll_XML_ctx *XMLCtx = data;
+
+
+ strcpy(XMLCtx->element, el);
+
+ switch (XMLCtx->level) {
+ case 0: if (strcasecmp(el,"edg_wll_LoadRequest")) unexp()
+ break;
+ case 1: if (strcasecmp(el,"server_file")) unexp()
+ break;
+ default: unexp()
+ break;
+ }
+ XMLCtx->level++;
+}
+
+
+
+static void startNotifRequest(void *data, const char *el, const char **attr)
+{
+ edg_wll_XML_ctx *XMLCtx = data;
+
+
+ strcpy(XMLCtx->element, el);
+
+ switch (XMLCtx->level) {
+ case 0: if (!strcasecmp(el,"edg_wll_NotifRequest") && attr[0] && attr[1]) {
+ if (strcmp(attr[0],"function")) { unexp() break;}
+ else XMLCtx->notifFunction = strdup(attr[1]);
+ }
+ else unexp()
+ break;
+ case 1: if (!strcasecmp(el,"and")) {
+ XMLCtx->jobQueryRec_begin = XML_GetCurrentByteIndex(XMLCtx->p);
+ }
+ else if ( (strcasecmp(el,"notifId")) && (strcasecmp(el,"clientAddress")) &&
+ (strcasecmp(el,"notifChangeOp")) ) unexp()
+ break;
+ case 2: /* fall through */
+ case 3: /* do not check xml tags, processed in startJobQueryRec */
+ case 4: break;
+ default: unexp()
+ break;
+ }
+ XMLCtx->level++;
+}
+
+#undef unexp
+
+
+static void char_handler(void *data, const char *s, int len)
+{
+ edg_wll_XML_ctx *XMLCtx = data;
+ int i, found = -1, temp_len1;
+ char *temp_s, *temp_s1;
+
+
+ /* if date are only spaces, t\, \r, \n ... don't bother with them */
+ for (i=0; i<len; i++)
+ if (!isspace(s[i])) { found = i; break; }
+ if (found == -1) return;
+
+ temp_s = malloc(len+1);
+
+ /* otherwise use them */
+ memcpy(temp_s,s,len);
+ temp_s[len] = 0;
+ temp_s1 = edg_wll_UnescapeXML((const char *) temp_s);
+ temp_len1 = strlen(temp_s1);
+
+ if (XMLCtx->char_buf_len) XMLCtx->char_buf =
+ realloc(XMLCtx->char_buf,XMLCtx->char_buf_len+temp_len1 + 1);
+ else XMLCtx->char_buf = malloc(temp_len1 + 1);
+
+ memcpy(XMLCtx->char_buf+XMLCtx->char_buf_len,temp_s1,temp_len1 + 1);
+ XMLCtx->char_buf_len += temp_len1;
+ free(temp_s1);
+ free(temp_s);
+}
+
+
+
+static void endJobQueryRec(void *data, const char *el UNUSED_VAR)
+{
+ edg_wll_XML_ctx *XMLCtx = data;
+ char *e;
+
+
+ if (XMLCtx->level == 4 &&
+ XMLCtx->job_conditions != NULL &&
+ XMLCtx->job_conditions[XMLCtx->row] != NULL) {
+ switch (XMLCtx->job_conditions[XMLCtx->row][XMLCtx->position].attr) {
+ case EDG_WLL_QUERY_ATTR_JOBID:
+ case EDG_WLL_QUERY_ATTR_PARENT:
+ if ( (XMLCtx->job_conditions[XMLCtx->row][XMLCtx->position].value.j =
+ edg_wll_from_string_to_jobid(XMLCtx)) == NULL )
+ {
+ if (XMLCtx->errtxt) {
+ asprintf(&e,"%s\n%s: invalid JobId at line %d",
+ XMLCtx->errtxt, XMLCtx->char_buf,
+ XML_GetCurrentLineNumber(XMLCtx->p));
+ free(XMLCtx->errtxt);
+ } else asprintf(&e,"%s: invalid JobId at line %d",
+ XMLCtx->char_buf,XML_GetCurrentLineNumber(XMLCtx->p));
+ XMLCtx->errtxt = e;
+ }
+ break;
+ case EDG_WLL_QUERY_ATTR_OWNER:
+ // XXX - this is way how to pass NULL, user will be extracted from ssl partner later
+ if (XMLCtx->char_buf != NULL && !strcmp(XMLCtx->char_buf,"NULL")) {
+ XMLCtx->job_conditions[XMLCtx->row][XMLCtx->position].value.c = NULL;
+ break;
+ }
+ else /* fall through */
+ case EDG_WLL_QUERY_ATTR_LOCATION:
+ case EDG_WLL_QUERY_ATTR_DESTINATION:
+ case EDG_WLL_QUERY_ATTR_USERTAG:
+ XMLCtx->job_conditions[XMLCtx->row][XMLCtx->position].value.c =
+ edg_wll_from_string_to_string(XMLCtx);
+ break;
+ case EDG_WLL_QUERY_ATTR_STATUS:
+ if ( !XMLCtx->bound )
+ {
+ XMLCtx->job_conditions[XMLCtx->row][XMLCtx->position].value.i =
+ edg_wll_from_string_to_edg_wll_JobStatCode(XMLCtx);
+ XMLCtx->bound++;
+ }
+ else
+ XMLCtx->job_conditions[XMLCtx->row][XMLCtx->position].value2.i =
+ edg_wll_from_string_to_edg_wll_JobStatCode(XMLCtx);
+
+ break;
+ case EDG_WLL_QUERY_ATTR_DONECODE:
+ case EDG_WLL_QUERY_ATTR_EXITCODE:
+ case EDG_WLL_QUERY_ATTR_RESUBMITTED:
+ if ( !XMLCtx->bound )
+ {
+ XMLCtx->job_conditions[XMLCtx->row][XMLCtx->position].value.i =
+ edg_wll_from_string_to_int(XMLCtx);
+ XMLCtx->bound++;
+ }
+ else
+ XMLCtx->job_conditions[XMLCtx->row][XMLCtx->position].value2.i =
+ edg_wll_from_string_to_int(XMLCtx);
+
+ break;
+ case EDG_WLL_QUERY_ATTR_TIME:
+ if ( !XMLCtx->bound )
+ {
+ XMLCtx->job_conditions[XMLCtx->row][XMLCtx->position].value.t.tv_sec =
+ edg_wll_from_string_to_time_t(XMLCtx);
+ XMLCtx->bound++;
+ }
+ else
+ XMLCtx->job_conditions[XMLCtx->row][XMLCtx->position].value2.t.tv_sec =
+ edg_wll_from_string_to_time_t(XMLCtx);
+ break;
+ default:
+ edg_wll_freeBuf(XMLCtx);
+ XMLCtx->level--;
+ if (XMLCtx->errtxt) {
+ asprintf(&e,"%s\n%s: invalid attribute type at line %d",
+ XMLCtx->errtxt, XMLCtx->char_buf,
+ XML_GetCurrentLineNumber(XMLCtx->p));
+ free(XMLCtx->errtxt);
+ } else asprintf(&e,"%s: invalid attribute type at line %d",
+ XMLCtx->char_buf,XML_GetCurrentLineNumber(XMLCtx->p));
+ XMLCtx->errtxt = e;
+ break;
+ }
+ }
+ XMLCtx->char_buf = NULL;
+ XMLCtx->char_buf_len = 0;
+ XMLCtx->level--;
+}
+
+
+
+static void endQueryJobsRequest(void *data, const char *el UNUSED_VAR)
+{
+ edg_wll_XML_ctx *XMLCtx = data;
+
+
+ if (XMLCtx->level == 2) {
+ if (!strcmp(XMLCtx->element,"flags") && XMLCtx->char_buf) {
+ // XXX: check if it works
+ XMLCtx->flags = edg_wll_string_to_stat_flags(XMLCtx->char_buf);
+ }
+ else if (!strcmp(el,"and")) {
+ long len = (XML_GetCurrentByteIndex(XMLCtx->p) + XML_GetCurrentByteCount(XMLCtx->p))
+ - XMLCtx->jobQueryRec_begin;
+
+ parseJobQueryRec(XMLCtx->ctx, XMLCtx->message_body + XMLCtx->jobQueryRec_begin, len,
+ &XMLCtx->job_conditions);
+ }
+ }
+ XMLCtx->char_buf = NULL;
+ XMLCtx->char_buf_len = 0;
+ XMLCtx->level--;
+}
+
+
+static void endQueryEventsRequest(void *data, const char *el UNUSED_VAR)
+{
+ edg_wll_XML_ctx *XMLCtx = data;
+ char *e;
+
+ if (XMLCtx->level == 2) {
+ if (!strcmp(XMLCtx->element,"orJobConditions")) {
+ /* make end-of-row */
+ XMLCtx->job_conditions[XMLCtx->row] = realloc(XMLCtx->job_conditions[XMLCtx->row],
+ (++XMLCtx->position+1)*sizeof(**XMLCtx->job_conditions));
+ memset(&XMLCtx->job_conditions[XMLCtx->row][XMLCtx->position],0,sizeof(**XMLCtx->job_conditions));
+ }
+ else if (!strcmp(XMLCtx->element,"orEventConditions")) {
+ /* make end-of-row */
+ XMLCtx->event_conditions[XMLCtx->row2] = realloc(XMLCtx->event_conditions[XMLCtx->row2],
+ (++XMLCtx->position2+1)*sizeof(**XMLCtx->event_conditions));
+ memset(&XMLCtx->event_conditions[XMLCtx->row2][XMLCtx->position2],0,sizeof(**XMLCtx->event_conditions));
+ }
+ }
+ else if (XMLCtx->level == 5) {
+ if (XMLCtx->type == EDG_WLL_QUERY_TYPE_JOB_CONDITION &&
+ XMLCtx->job_conditions != NULL &&
+ XMLCtx->job_conditions[XMLCtx->row] !=NULL) {
+ switch (XMLCtx->job_conditions[XMLCtx->row][XMLCtx->position].attr) {
+ case EDG_WLL_QUERY_ATTR_JOBID:
+ case EDG_WLL_QUERY_ATTR_PARENT:
+ if ( (XMLCtx->job_conditions[XMLCtx->row][XMLCtx->position].value.j =
+ edg_wll_from_string_to_jobid(XMLCtx)) == NULL )
+ {
+ if (XMLCtx->errtxt) {
+ asprintf(&e,"%s\n%s: invalid JobId at line %d",
+ XMLCtx->errtxt, XMLCtx->char_buf,
+ XML_GetCurrentLineNumber(XMLCtx->p));
+ free(XMLCtx->errtxt);
+ } else asprintf(&e,"%s: invalid JobId at line %d",
+ XMLCtx->char_buf,XML_GetCurrentLineNumber(XMLCtx->p));
+ XMLCtx->errtxt = e;
+ }
+ break;
+ case EDG_WLL_QUERY_ATTR_OWNER:
+ case EDG_WLL_QUERY_ATTR_LOCATION:
+ case EDG_WLL_QUERY_ATTR_DESTINATION:
+ case EDG_WLL_QUERY_ATTR_USERTAG:
+ XMLCtx->job_conditions[XMLCtx->row][XMLCtx->position].value.c =
+ edg_wll_from_string_to_string(XMLCtx);
+ break;
+ case EDG_WLL_QUERY_ATTR_STATUS:
+ case EDG_WLL_QUERY_ATTR_DONECODE:
+ case EDG_WLL_QUERY_ATTR_EXITCODE:
+ case EDG_WLL_QUERY_ATTR_RESUBMITTED:
+ if ( !XMLCtx->bound )
+ {
+ XMLCtx->job_conditions[XMLCtx->row][XMLCtx->position].value.i =
+ edg_wll_from_string_to_int(XMLCtx);
+ XMLCtx->bound++;
+ }
+ else
+ XMLCtx->job_conditions[XMLCtx->row][XMLCtx->position].value2.i =
+ edg_wll_from_string_to_int(XMLCtx);
+ break;
+ case EDG_WLL_QUERY_ATTR_TIME:
+ if ( !XMLCtx->bound )
+ {
+ XMLCtx->job_conditions[XMLCtx->row][XMLCtx->position].value.t.tv_sec =
+ edg_wll_from_string_to_time_t(XMLCtx);
+ XMLCtx->bound++;
+ }
+ else
+ XMLCtx->job_conditions[XMLCtx->row][XMLCtx->position].value2.t.tv_sec =
+ edg_wll_from_string_to_time_t(XMLCtx);
+ break;
+ default:
+ edg_wll_freeBuf(XMLCtx);
+ XMLCtx->level--;
+ if (XMLCtx->errtxt) {
+ asprintf(&e,"%s\n%s: invalid attribute type at line %d",
+ XMLCtx->errtxt, XMLCtx->char_buf,
+ XML_GetCurrentLineNumber(XMLCtx->p));
+ free(XMLCtx->errtxt);
+ } else asprintf(&e,"%s: invalid attribute type at line %d",
+ XMLCtx->char_buf,XML_GetCurrentLineNumber(XMLCtx->p));
+ XMLCtx->errtxt = e;
+ break;
+ }
+ }
+ else if (XMLCtx->type == EDG_WLL_QUERY_TYPE_EVENT_CONDITION &&
+ XMLCtx->event_conditions != NULL &&
+ XMLCtx->event_conditions[XMLCtx->row2] != NULL) {
+ switch (XMLCtx->event_conditions[XMLCtx->row2][XMLCtx->position2].attr) {
+ case EDG_WLL_QUERY_ATTR_TIME:
+ if ( !XMLCtx->bound )
+ {
+ XMLCtx->event_conditions[XMLCtx->row2][XMLCtx->position2].value.t.tv_sec =
+ edg_wll_from_string_to_time_t(XMLCtx);
+ XMLCtx->bound++;
+ }
+ else
+ XMLCtx->event_conditions[XMLCtx->row2][XMLCtx->position2].value2.t.tv_sec =
+ edg_wll_from_string_to_time_t(XMLCtx);
+ break;
+ case EDG_WLL_QUERY_ATTR_LEVEL:
+ case EDG_WLL_QUERY_ATTR_SOURCE:
+ case EDG_WLL_QUERY_ATTR_EVENT_TYPE:
+ if ( !XMLCtx->bound )
+ {
+ XMLCtx->event_conditions[XMLCtx->row2][XMLCtx->position2].value.i =
+ edg_wll_from_string_to_int(XMLCtx);
+ XMLCtx->bound++;
+ }
+ else
+ XMLCtx->event_conditions[XMLCtx->row2][XMLCtx->position2].value2.i =
+ edg_wll_from_string_to_int(XMLCtx);
+ break;
+ case EDG_WLL_QUERY_ATTR_HOST:
+ case EDG_WLL_QUERY_ATTR_INSTANCE:
+ case EDG_WLL_QUERY_ATTR_USERTAG:
+ XMLCtx->event_conditions[XMLCtx->row2][XMLCtx->position2].value.c =
+ edg_wll_from_string_to_string(XMLCtx);
+ break;
+ default:
+ edg_wll_freeBuf(XMLCtx);
+ XMLCtx->level--;
+ if (XMLCtx->errtxt) {
+ asprintf(&e,"%s\n%s: invalid attribute type at line %d",
+ XMLCtx->errtxt, XMLCtx->char_buf,
+ XML_GetCurrentLineNumber(XMLCtx->p));
+ free(XMLCtx->errtxt);
+ } else asprintf(&e,"%s: invalid attribute type at line %d",
+ XMLCtx->char_buf,XML_GetCurrentLineNumber(XMLCtx->p));
+ XMLCtx->errtxt = e;
+ break;
+ }
+ }
+
+ XMLCtx->char_buf = NULL;
+ XMLCtx->char_buf_len = 0;
+ }
+ XMLCtx->level--;
+}
+
+
+static void endPurgeRequest(void *data, const char *el UNUSED_VAR)
+{
+ edg_wll_XML_ctx *XMLCtx = data;
+ char *e;
+ int index;
+
+ if (XMLCtx->level == 2) {
+ if (!strcmp(XMLCtx->element,"flags"))
+ XMLCtx->purgeRequestGlobal.flags = edg_wll_string_to_purge_flags(XMLCtx->char_buf);
+ }
+ else if (XMLCtx->level == 3) {
+ if (!strcmp(XMLCtx->element,"jobId") && XMLCtx->purgeRequestGlobal.jobs != NULL) {
+ if ( (XMLCtx->purgeRequestGlobal.jobs[XMLCtx->position++] =
+ edg_wll_from_string_to_string(XMLCtx)) == NULL )
+ {
+ if (XMLCtx->errtxt) {
+ asprintf(&e,"%s\n%s: invalid JobId at line %d",
+ XMLCtx->errtxt, XMLCtx->char_buf,
+ XML_GetCurrentLineNumber(XMLCtx->p));
+ free(XMLCtx->errtxt);
+ } else asprintf(&e,"%s: invalid JobId at line %d",
+ XMLCtx->char_buf,XML_GetCurrentLineNumber(XMLCtx->p));
+ XMLCtx->errtxt = e;
+ }
+ }
+ else if ( ((index = XMLCtx->tagToIndex(XMLCtx->element)) >= 0 ) && XMLCtx->char_buf ) {
+ XMLCtx->purgeRequestGlobal.timeout[index] =
+ edg_wll_from_string_to_time_t(XMLCtx);
+ }
+ }
+
+ XMLCtx->char_buf = NULL;
+ XMLCtx->char_buf_len = 0;
+ XMLCtx->level--;
+}
+
+
+static void endDumpRequest(void *data, const char *el UNUSED_VAR)
+{
+ edg_wll_XML_ctx *XMLCtx = data;
+
+ if (XMLCtx->level == 2) {
+ if (!strcmp(XMLCtx->element,"from")) {
+ if (isdigit(XMLCtx->char_buf[0]))
+ XMLCtx->dumpRequestGlobal.from = edg_wll_from_string_to_time_t(XMLCtx);
+ else
+ XMLCtx->dumpRequestGlobal.from = edg_wll_StringToDumpConst(XMLCtx->char_buf);
+ }
+ else if (!strcmp(XMLCtx->element,"to")) {
+ if (isdigit(XMLCtx->char_buf[0]))
+ XMLCtx->dumpRequestGlobal.to = edg_wll_from_string_to_time_t(XMLCtx);
+ else
+ XMLCtx->dumpRequestGlobal.to = edg_wll_StringToDumpConst(XMLCtx->char_buf);
+ }
+ }
+
+ XMLCtx->char_buf = NULL;
+ XMLCtx->char_buf_len = 0;
+ XMLCtx->level--;
+}
+
+
+
+static void endLoadRequest(void *data, const char *el UNUSED_VAR)
+{
+ edg_wll_XML_ctx *XMLCtx = data;
+
+ if (XMLCtx->level == 2) {
+ if (!strcmp(XMLCtx->element,"server_file"))
+ XMLCtx->loadRequestGlobal.server_file = edg_wll_from_string_to_string(XMLCtx);
+ }
+
+ XMLCtx->char_buf = NULL;
+ XMLCtx->char_buf_len = 0;
+ XMLCtx->level--;
+}
+
+
+
+static void endNotifRequest(void *data, const char *el UNUSED_VAR)
+{
+ edg_wll_XML_ctx *XMLCtx = data;
+ char *pom;
+
+ if (XMLCtx->level == 2) {
+ if (!strcmp(XMLCtx->element,"notifId")) {
+ pom = edg_wll_from_string_to_string(XMLCtx);
+ edg_wll_NotifIdParse(pom, &XMLCtx->notifId);
+ free(pom);
+ }
+ else if (!strcmp(XMLCtx->element,"clientAddress")) {
+ XMLCtx->notifClientAddress = edg_wll_from_string_to_string(XMLCtx);
+ }
+ else if (!strcmp(XMLCtx->element,"notifChangeOp")) {
+ pom = edg_wll_from_string_to_string(XMLCtx);
+ XMLCtx->notifChangeOp = edg_wll_StringToNotifChangeOp(pom);
+ free(pom);
+ }
+ else if (!strcmp(el,"and")) {
+ long len = (XML_GetCurrentByteIndex(XMLCtx->p) + XML_GetCurrentByteCount(XMLCtx->p))
+ - XMLCtx->jobQueryRec_begin;
+
+ parseJobQueryRec(XMLCtx->ctx, XMLCtx->message_body + XMLCtx->jobQueryRec_begin, len,
+ &XMLCtx->job_conditions);
+ }
+ }
+
+ XMLCtx->char_buf = NULL;
+ XMLCtx->char_buf_len = 0;
+ XMLCtx->level--;
+}
+
+
+
+int parseJobQueryRec(edg_wll_Context ctx, const char *messageBody, long len, edg_wll_QueryRec ***conditions)
+{
+ int ret;
+ edg_wll_XML_ctx XMLCtx;
+ XML_Char *encoding = "ISO-8859-1";
+
+ errno = 0;
+ edg_wll_initXMLCtx(&XMLCtx);
+ XMLCtx.row = -1;
+ XMLCtx.ctx = ctx;
+ edg_wll_ResetError(ctx);
+
+
+ /* initialize parser */
+ XMLCtx.p = XML_ParserCreate(encoding);
+ XML_SetElementHandler(XMLCtx.p, startJobQueryRec, endJobQueryRec);
+ XML_SetCharacterDataHandler(XMLCtx.p, char_handler);
+ XML_SetUserData(XMLCtx.p, (void *) &XMLCtx);
+
+
+ if (! XML_Parse(XMLCtx.p, messageBody, len, 1)) {
+ char *errorMessage;
+
+ asprintf(&errorMessage, "Parse error at line %d:\n%s\n",
+ XML_GetCurrentLineNumber(XMLCtx.p),
+ XML_ErrorString(XML_GetErrorCode(XMLCtx.p)));
+
+ edg_wll_SetError(ctx, EDG_WLL_ERROR_XML_PARSE, errorMessage);
+ free(errorMessage);
+ } else if (XMLCtx.errtxt) edg_wll_SetError(ctx, EDG_WLL_ERROR_XML_PARSE, XMLCtx.errtxt);
+
+
+ if ((ret = edg_wll_Error(ctx,NULL,NULL))) {
+ int i,j;
+
+ if (XMLCtx.job_conditions) {
+ for (j = 0; XMLCtx.job_conditions[j]; j++) {
+ for (i = 0; (XMLCtx.job_conditions[j][i].attr != EDG_WLL_QUERY_ATTR_UNDEF); i++ )
+ edg_wll_QueryRecFree(&XMLCtx.job_conditions[j][i]);
+ free(XMLCtx.job_conditions[j]);
+ }
+ free(XMLCtx.job_conditions);
+ }
+
+ /* empty list terminators */
+ conditions[0] = NULL;
+ } else {
+ *conditions = XMLCtx.job_conditions;
+ }
+
+
+ XML_ParserFree(XMLCtx.p);
+ edg_wll_freeXMLCtx(&XMLCtx);
+ return ret;
+}
+
+
+/* parse queryJobs request from client */
+int parseQueryJobsRequest(edg_wll_Context ctx, char *messageBody, edg_wll_QueryRec ***conditions, int *flags)
+{
+ int ret;
+ edg_wll_XML_ctx XMLCtx;
+ XML_Char *encoding = "ISO-8859-1";
+
+ errno = 0;
+ edg_wll_initXMLCtx(&XMLCtx);
+ XMLCtx.ctx = ctx;
+ XMLCtx.message_body = messageBody;
+ XMLCtx.position = 0;
+ edg_wll_ResetError(ctx);
+
+
+ /* initialize parser */
+ XMLCtx.p = XML_ParserCreate(encoding);
+ XML_SetElementHandler(XMLCtx.p, startQueryJobsRequest, endQueryJobsRequest);
+ XML_SetCharacterDataHandler(XMLCtx.p, char_handler);
+ XML_SetUserData(XMLCtx.p, (void *) &XMLCtx);
+
+
+ if (! XML_Parse(XMLCtx.p, messageBody, strlen(messageBody), 1)) {
+ char *errorMessage;
+
+ asprintf(&errorMessage, "Parse error at line %d:\n%s\n",
+ XML_GetCurrentLineNumber(XMLCtx.p),
+ XML_ErrorString(XML_GetErrorCode(XMLCtx.p)));
+
+ edg_wll_SetError(ctx, EDG_WLL_ERROR_XML_PARSE, errorMessage);
+ free(errorMessage);
+ } else if (XMLCtx.errtxt) edg_wll_SetError(ctx, EDG_WLL_ERROR_XML_PARSE, XMLCtx.errtxt);
+
+
+ if ((ret = edg_wll_Error(ctx,NULL,NULL))) {
+ int i,j;
+
+ if (XMLCtx.job_conditions) {
+ for (j = 0; XMLCtx.job_conditions[j]; j++) {
+ for (i = 0; (XMLCtx.job_conditions[j][i].attr != EDG_WLL_QUERY_ATTR_UNDEF); i++ )
+ edg_wll_QueryRecFree(&XMLCtx.job_conditions[j][i]);
+ free(XMLCtx.job_conditions[j]);
+ }
+ free(XMLCtx.job_conditions);
+ }
+
+ /* empty list terminators */
+ conditions[0] = NULL;
+ *flags = 0;
+ } else {
+ *conditions = XMLCtx.job_conditions;
+ *flags = XMLCtx.flags;
+ }
+
+
+ XML_ParserFree(XMLCtx.p);
+ edg_wll_freeXMLCtx(&XMLCtx);
+ return ret;
+}
+
+
+/* parse queryEvents request from client */
+int parseQueryEventsRequest(edg_wll_Context ctx, char *messageBody, edg_wll_QueryRec ***job_conditions, edg_wll_QueryRec ***event_conditions)
+{
+ int ret;
+ edg_wll_XML_ctx XMLCtx;
+ XML_Char *encoding = "ISO-8859-1";
+
+ errno = 0;
+ edg_wll_initXMLCtx(&XMLCtx);
+ XMLCtx.row = -1;
+ XMLCtx.row2 = -1;
+ XMLCtx.ctx = ctx;
+ edg_wll_ResetError(ctx);
+
+
+ /* initialize parser */
+ XMLCtx.p = XML_ParserCreate(encoding);
+ XML_SetElementHandler(XMLCtx.p, startQueryEventsRequest, endQueryEventsRequest);
+ XML_SetCharacterDataHandler(XMLCtx.p, char_handler);
+ XML_SetUserData(XMLCtx.p, (void *) &XMLCtx);
+
+
+ if (! XML_Parse(XMLCtx.p, messageBody, strlen(messageBody), 1)) {
+ char *errorMessage;
+
+ asprintf(&errorMessage, "Parse error at line %d:\n%s\n",
+ XML_GetCurrentLineNumber(XMLCtx.p),
+ XML_ErrorString(XML_GetErrorCode(XMLCtx.p)));
+
+ edg_wll_SetError(ctx, EDG_WLL_ERROR_XML_PARSE, errorMessage);
+ free(errorMessage);
+ } else if (XMLCtx.errtxt) edg_wll_SetError(ctx, EDG_WLL_ERROR_XML_PARSE, XMLCtx.errtxt);
+
+
+ if ((ret = edg_wll_Error(ctx,NULL,NULL))) {
+ int i,j;
+
+ if (XMLCtx.job_conditions) {
+ for (j = 0; XMLCtx.job_conditions[j]; j++) {
+ for (i = 0 ; (XMLCtx.job_conditions[j][i].attr != EDG_WLL_QUERY_ATTR_UNDEF); i++ )
+ edg_wll_QueryRecFree(&XMLCtx.job_conditions[j][i]);
+ free(XMLCtx.job_conditions[j]);
+ }
+ free(XMLCtx.job_conditions);
+ }
+ if (XMLCtx.event_conditions) {
+ for (j = 0; XMLCtx.event_conditions[j]; j++) {
+ for (i = 0 ; (XMLCtx.event_conditions[j][i].attr != EDG_WLL_QUERY_ATTR_UNDEF); i++ )
+ edg_wll_QueryRecFree(&XMLCtx.event_conditions[j][i]);
+ free(XMLCtx.event_conditions[j]);
+ }
+ free(XMLCtx.event_conditions);
+ }
+
+ /* empty list terminators */
+ job_conditions[0] = NULL;
+ event_conditions[0] = NULL;
+ } else {
+ *job_conditions = XMLCtx.job_conditions;
+ *event_conditions = XMLCtx.event_conditions;
+ }
+
+
+ XML_ParserFree(XMLCtx.p);
+ edg_wll_freeXMLCtx(&XMLCtx);
+ return ret;
+}
+
+
+
+/* parse purge request from client */
+int parsePurgeRequest(edg_wll_Context ctx, char *messageBody, int (*tagToIndex)(), edg_wll_PurgeRequest *request)
+{
+ int ret;
+ edg_wll_XML_ctx XMLCtx;
+ XML_Char *encoding = "ISO-8859-1";
+
+ errno = 0;
+ edg_wll_initXMLCtx(&XMLCtx);
+ XMLCtx.ctx = ctx;
+ edg_wll_ResetError(ctx);
+ XMLCtx.tagToIndex = tagToIndex;
+
+
+ /* initialize parser */
+ XMLCtx.p = XML_ParserCreate(encoding);
+ XML_SetElementHandler(XMLCtx.p, startPurgeRequest, endPurgeRequest);
+ XML_SetCharacterDataHandler(XMLCtx.p, char_handler);
+ XML_SetUserData(XMLCtx.p, (void *) &XMLCtx);
+
+
+ if (! XML_Parse(XMLCtx.p, messageBody, strlen(messageBody), 1)) {
+ char *errorMessage;
+
+ asprintf(&errorMessage, "Parse error at line %d:\n%s\n",
+ XML_GetCurrentLineNumber(XMLCtx.p),
+ XML_ErrorString(XML_GetErrorCode(XMLCtx.p)));
+
+ edg_wll_SetError(ctx, EDG_WLL_ERROR_XML_PARSE, errorMessage);
+ free(errorMessage);
+ } else if (XMLCtx.errtxt) edg_wll_SetError(ctx, EDG_WLL_ERROR_XML_PARSE, XMLCtx.errtxt);
+
+
+ if ((ret = edg_wll_Error(ctx,NULL,NULL))) {
+ int i;
+
+ if (XMLCtx.purgeRequestGlobal.jobs) {
+ for (i=0; XMLCtx.purgeRequestGlobal.jobs[i]; i++)
+ free(XMLCtx.purgeRequestGlobal.jobs[i]);
+ free(XMLCtx.purgeRequestGlobal.jobs);
+ }
+ memset(request,0,sizeof(*request));
+
+ } else {
+ memcpy(request, &XMLCtx.purgeRequestGlobal, sizeof(XMLCtx.purgeRequestGlobal));
+ }
+
+
+ XML_ParserFree(XMLCtx.p);
+ edg_wll_freeXMLCtx(&XMLCtx);
+ return ret;
+}
+
+
+
+/* parse dump request from client */
+int parseDumpRequest(edg_wll_Context ctx, char *messageBody, edg_wll_DumpRequest *request)
+{
+ int ret;
+ edg_wll_XML_ctx XMLCtx;
+ XML_Char *encoding = "ISO-8859-1";
+
+ errno = 0;
+ edg_wll_initXMLCtx(&XMLCtx);
+ XMLCtx.ctx = ctx;
+ edg_wll_ResetError(ctx);
+
+
+ /* initialize parser */
+ XMLCtx.p = XML_ParserCreate(encoding);
+ XML_SetElementHandler(XMLCtx.p, startDumpRequest, endDumpRequest);
+ XML_SetCharacterDataHandler(XMLCtx.p, char_handler);
+ XML_SetUserData(XMLCtx.p, (void *) &XMLCtx);
+
+
+ if (! XML_Parse(XMLCtx.p, messageBody, strlen(messageBody), 1)) {
+ char *errorMessage;
+
+ asprintf(&errorMessage, "Parse error at line %d:\n%s\n",
+ XML_GetCurrentLineNumber(XMLCtx.p),
+ XML_ErrorString(XML_GetErrorCode(XMLCtx.p)));
+
+ edg_wll_SetError(ctx, EDG_WLL_ERROR_XML_PARSE, errorMessage);
+ free(errorMessage);
+ } else if (XMLCtx.errtxt) edg_wll_SetError(ctx, EDG_WLL_ERROR_XML_PARSE, XMLCtx.errtxt);
+
+
+ if ((ret = edg_wll_Error(ctx,NULL,NULL)))
+ memset(request,0,sizeof(*request));
+
+ else {
+ memcpy(request, &XMLCtx.dumpRequestGlobal, sizeof(XMLCtx.dumpRequestGlobal));
+ }
+
+
+ XML_ParserFree(XMLCtx.p);
+ edg_wll_freeXMLCtx(&XMLCtx);
+ return ret;
+}
+
+/* parse load request from client */
+int parseLoadRequest(edg_wll_Context ctx, char *messageBody, edg_wll_LoadRequest *request)
+{
+ int ret;
+ edg_wll_XML_ctx XMLCtx;
+ XML_Char *encoding = "ISO-8859-1";
+
+ errno = 0;
+ edg_wll_initXMLCtx(&XMLCtx);
+ XMLCtx.ctx = ctx;
+ edg_wll_ResetError(ctx);
+
+
+ /* initialize parser */
+ XMLCtx.p = XML_ParserCreate(encoding);
+ XML_SetElementHandler(XMLCtx.p, startLoadRequest, endLoadRequest);
+ XML_SetCharacterDataHandler(XMLCtx.p, char_handler);
+ XML_SetUserData(XMLCtx.p, (void *) &XMLCtx);
+
+
+ if (! XML_Parse(XMLCtx.p, messageBody, strlen(messageBody), 1)) {
+ char *errorMessage;
+
+ asprintf(&errorMessage, "Parse error at line %d:\n%s\n",
+ XML_GetCurrentLineNumber(XMLCtx.p),
+ XML_ErrorString(XML_GetErrorCode(XMLCtx.p)));
+
+ edg_wll_SetError(ctx, EDG_WLL_ERROR_XML_PARSE, errorMessage);
+ free(errorMessage);
+ } else if (XMLCtx.errtxt) edg_wll_SetError(ctx, EDG_WLL_ERROR_XML_PARSE, XMLCtx.errtxt);
+
+
+ if ((ret = edg_wll_Error(ctx,NULL,NULL)))
+ memset(request,0,sizeof(*request));
+
+ else {
+ memcpy(request, &XMLCtx.loadRequestGlobal, sizeof(XMLCtx.loadRequestGlobal));
+ }
+
+
+ XML_ParserFree(XMLCtx.p);
+ edg_wll_freeXMLCtx(&XMLCtx);
+ return ret;
+}
+
+
+
+/* parse Notif request from client */
+int parseNotifRequest(edg_wll_Context ctx, char *messageBody, char **function, edg_wll_NotifId *notifId, char **address, edg_wll_NotifChangeOp *op, edg_wll_QueryRec ***conditions)
+{
+ int ret;
+ edg_wll_XML_ctx XMLCtx;
+ XML_Char *encoding = "ISO-8859-1";
+
+
+ /* returns emty variables as default; only some variables will be filled in */
+ /* depending on vaule of XMLCtx.notifFunction */
+ *function = NULL;
+ *notifId = NULL;
+ *address = NULL;
+ *op = EDG_WLL_NOTIF_NOOP;
+ *conditions = NULL;
+
+ errno = 0;
+ edg_wll_initXMLCtx(&XMLCtx);
+ XMLCtx.ctx = ctx;
+ XMLCtx.message_body = messageBody;
+ edg_wll_ResetError(ctx);
+
+
+ /* initialize parser */
+ XMLCtx.p = XML_ParserCreate(encoding);
+ XML_SetElementHandler(XMLCtx.p, startNotifRequest, endNotifRequest);
+ XML_SetCharacterDataHandler(XMLCtx.p, char_handler);
+ XML_SetUserData(XMLCtx.p, (void *) &XMLCtx);
+
+
+ if (! XML_Parse(XMLCtx.p, messageBody, strlen(messageBody), 1)) {
+ char *errorMessage;
+
+ asprintf(&errorMessage, "Parse error at line %d:\n%s\n",
+ XML_GetCurrentLineNumber(XMLCtx.p),
+ XML_ErrorString(XML_GetErrorCode(XMLCtx.p)));
+
+ edg_wll_SetError(ctx, EDG_WLL_ERROR_XML_PARSE, errorMessage);
+ free(errorMessage);
+ } else if (XMLCtx.errtxt) edg_wll_SetError(ctx, EDG_WLL_ERROR_XML_PARSE, XMLCtx.errtxt);
+
+
+ if ((ret = edg_wll_Error(ctx,NULL,NULL))) {
+ int i,j;
+
+ if (XMLCtx.job_conditions) {
+ for (j = 0; XMLCtx.job_conditions[j]; j++) {
+ for (i = 0; (XMLCtx.job_conditions[j][i].attr != EDG_WLL_QUERY_ATTR_UNDEF); i++ )
+ edg_wll_QueryRecFree(&XMLCtx.job_conditions[j][i]);
+ free(XMLCtx.job_conditions[j]);
+ }
+ free(XMLCtx.job_conditions);
+ }
+ free(XMLCtx.notifFunction);
+ edg_wll_NotifIdFree(&XMLCtx.notifId);
+ free(XMLCtx.notifClientAddress);
+
+ *function = NULL;
+ *notifId = NULL;
+ *address = NULL;
+ *op = EDG_WLL_NOTIF_NOOP;
+ *conditions = NULL;
+ } else {
+ *function = XMLCtx.notifFunction;
+ *notifId = XMLCtx.notifId;
+ *address = XMLCtx.notifClientAddress;
+ *op = XMLCtx.notifChangeOp;
+ *conditions = XMLCtx.job_conditions;
+ }
+
+
+ XML_ParserFree(XMLCtx.p);
+ edg_wll_freeXMLCtx(&XMLCtx);
+ return ret;
+}
+
+
+int edg_wll_QueryEventsToXML(edg_wll_Context ctx, edg_wll_Event *eventsOut, char **message)
+{
+ char *pomA, *pomB;
+ char **list = NULL;
+ int i = 0, len, tot_len = 0;
+ int *len_list = NULL;
+
+
+ while (eventsOut && eventsOut[i].any.type != EDG_WLL_EVENT_UNDEF) {
+ pomB = edg_wll_EventToString(eventsOut[i].any.type);
+ trio_asprintf(&pomA," <edg_wll_Event name=\"%|Xs\">\r\n", pomB);
+ free(pomB);
+ pomB = pomA;
+
+
+@@@{
+ selectType $event '_common_';
+ for (getFieldsOrdered $event) {
+ my $f = selectField $event $_;
+ my $ft = $f->{type};
+ my $n = $f->{null};
+ gen "\tedg_wll_add_$ft\_to_XMLBody(&pomB, eventsOut[i].any.$_, \"$_\", $n);\n";
+ }
+
+ gen "\tswitch (eventsOut[i].any.type) {\n";
+ for my $t (sort { $event->{order}->{$a} <=> $event->{order}->{$b} } getTypes $event) {
+ if ($t ne 'any') {
+ selectType $event $t;
+ my $u = uc $t;
+ gen "\t case EDG_WLL_EVENT_$u :\n";
+ for (getFieldsOrdered $event) {
+ my $f = selectField $event $_;
+ my $ft = $f->{type};
+ my $n = $f->{null};
+ $t = lcfirst $t;
+ gen "\t\tedg_wll_add_$ft\_to_XMLBody(&pomB, eventsOut[i].$t.$_, \"$_\", $n);\n";
+ }
+ gen "\t\tbreak;\n";
+ }
+ }
+ gen "\t default : break;\n";
+ gen "\t}\n";
+@@@}
+
+
+
+ len = asprintf(&pomA,"%s </edg_wll_Event>\r\n", pomB);
+ free(pomB);
+ i++;
+ tot_len += len;
+
+ list = (char **) realloc(list, i * sizeof(*list));
+ list[i-1] = pomA;
+ len_list = (int *) realloc(len_list, i * sizeof(*len_list));
+ len_list[i-1] = len;
+
+ }
+
+ /* list termination */
+ list = (char **) realloc(list, (i+1) * sizeof(*list));
+ list[i] = NULL;
+
+ /* test errors */
+ if (ctx->errDesc || ctx->errCode)
+ len = trio_asprintf(&pomB," code=\"%d\" desc=\"%|Xs\">\r\n",ctx->errCode,ctx->errDesc);
+ else
+ len = asprintf(&pomB,">\r\n");
+
+ /* glueing all list fields together & freeing the list */
+ pomA = (char *) malloc(tot_len * sizeof(char) +
+ sizeof(QUERY_EVENTS_BEGIN) + len + sizeof(QUERY_EVENTS_END) - 1);
+
+ memcpy(pomA, QUERY_EVENTS_BEGIN, sizeof(QUERY_EVENTS_BEGIN));
+ memcpy(pomA + sizeof(QUERY_EVENTS_BEGIN) - 1, pomB, len);
+ free(pomB);
+ pomB = pomA + sizeof(QUERY_EVENTS_BEGIN) + len - 1;
+
+ i = 0;
+ while (list[i]) {
+ memcpy(pomB, list[i], len_list[i] );
+ pomB += len_list[i];
+
+ /* freeing the list */
+ free(list[i]);
+
+ i++;
+ }
+
+ strcpy(pomB, QUERY_EVENTS_END);
+
+
+ free(list);
+ free(len_list);
+
+
+ *message = pomA;
+
+ return 0;
+}
+
+int edg_wll_QueryJobsToXML(edg_wll_Context ctx, edg_wlc_JobId *jobsIn, edg_wll_JobStat *statesIn, char **message)
+{
+ char *pomA, *pomB, *pomC;
+ char **list = NULL;
+ int i = 0, len, tot_len = 0, nres = 0;
+ int *len_list = NULL;
+
+
+ if (jobsIn) for (nres = 0; jobsIn[nres]; nres++);
+ else if (statesIn) for (nres = 0; statesIn[nres].state; nres++);
+
+ while (i < nres) {
+ trio_asprintf(&pomA,"\t<edg_wll_Job>\r\n");
+ pomB = pomA;
+
+ if (jobsIn) {
+ trio_asprintf(&pomA,"%s\t\t<jobId>%|Xs</jobId>\r\n",
+ pomB, pomC=edg_wlc_JobIdUnparse(jobsIn[i]));
+ free(pomC);
+ free(pomB);
+ pomB = pomA;
+ }
+
+ if (statesIn) {
+ edg_wll_JobStatusToXML(ctx, statesIn[i], &pomC);
+ trio_asprintf(&pomA,"%s\t\t%s",pomB,pomC);
+ }
+ else {
+ pomC = edg_wll_StatToString(EDG_WLL_JOB_UNKNOWN);
+ trio_asprintf(&pomA,"%s\t\t<jobStat name=\"%|Xs\">\r\n\r\n\t\t</jobStat>\r\n",
+ pomB, pomC);
+ }
+
+ free(pomB);
+ free(pomC);
+ pomB = pomA;
+
+
+ len = asprintf(&pomA,"%s\t</edg_wll_Job>\r\n", pomB);
+ free(pomB);
+ i++;
+ tot_len += len;
+
+ list = (char **) realloc(list, i * sizeof(*list));
+ list[i-1] = pomA;
+ len_list = (int *) realloc(len_list, i * sizeof(*len_list));
+ len_list[i-1] = len;
+ }
+
+ /* list termination */
+ list = (char **) realloc(list, (i+1) * sizeof(*list));
+ list[i] = NULL;
+
+ /* test errors */
+ if (ctx->errDesc || ctx->errCode)
+ len = trio_asprintf(&pomB," code=\"%d\" desc=\"%|Xs\">\r\n",ctx->errCode,ctx->errDesc);
+ else
+ len = asprintf(&pomB,">\r\n");
+
+ /* glueing all list fields together & freeing the list */
+ pomA = (char *) malloc(tot_len * sizeof(char) +
+ sizeof(QUERY_JOBS_BEGIN) + len + sizeof(QUERY_JOBS_END) - 1);
+
+ memcpy(pomA, QUERY_JOBS_BEGIN, sizeof(QUERY_JOBS_BEGIN));
+ memcpy((pomA + sizeof(QUERY_JOBS_BEGIN) - 1), pomB, len);
+ free(pomB);
+ pomB = pomA + sizeof(QUERY_JOBS_BEGIN) + len - 1;
+
+ i = 0;
+ while (list[i]) {
+ memcpy(pomB, list[i], len_list[i] );
+ pomB += len_list[i];
+
+ /* freeing the list */
+ free(list[i]);
+
+ i++;
+ }
+
+ strcpy(pomB, QUERY_JOBS_END);
+
+
+ free(list);
+ free(len_list);
+
+
+ *message = pomA;
+
+ return 0;
+}
+
+/* construct Message-Body of Response-Line for edg_wll_UserJobs */
+int edg_wll_UserJobsToXML(edg_wll_Context ctx, edg_wlc_JobId *jobsOut, char **message)
+{
+ char *pomA, *pomB;
+ char **list = NULL;
+ int i = 0, len, tot_len = 0;
+ int *len_list = NULL;
+
+
+ while (jobsOut[i]) {
+ len = trio_asprintf(&pomA," <jobId>%|Xs</jobId>\r\n",
+ pomB=edg_wlc_JobIdUnparse(jobsOut[i]));
+
+ free(pomB);
+
+ i++;
+ tot_len += len;
+
+ list = (char **) realloc(list, i * sizeof(*list));
+ list[i-1] = pomA;
+ pomA = NULL;
+ len_list = (int *) realloc(len_list, i * sizeof(*len_list));
+ len_list[i-1] = len;
+
+ }
+
+ /* list termination */
+ list = (char **) realloc(list, (i+1) * sizeof(*list));
+ list[i] = NULL;
+
+ /* test errors */
+ if (ctx->errDesc || ctx->errCode)
+ len = trio_asprintf(&pomB," code=\"%d\" desc=\"%|Xs\">\r\n",ctx->errCode,ctx->errDesc);
+ else
+ len = asprintf(&pomB,">\r\n");
+
+ /* glueing all list fields together & freeing the list */
+ pomA = (char *) malloc(tot_len * sizeof(char) +
+ sizeof(USERJOBS_BEGIN) + len + sizeof(USERJOBS_END) - 1);
+
+ memcpy(pomA, USERJOBS_BEGIN, sizeof(USERJOBS_BEGIN));
+ memcpy((pomA + sizeof(USERJOBS_BEGIN) - 1), pomB, len);
+ free(pomB);
+ pomB = pomA + sizeof(USERJOBS_BEGIN) + len - 1;
+
+ i = 0;
+ while (list[i]) {
+ memcpy(pomB, list[i], len_list[i] );
+ pomB += len_list[i];
+
+ /* freeing the list */
+ free(list[i]);
+
+ i++;
+ }
+
+ strcpy(pomB, USERJOBS_END);
+
+
+ free(list);
+ free(len_list);
+
+
+ *message = pomA;
+
+ return 0;
+}
+
+void edg_wll_add_stslist_to_XMLBody(edg_wll_Context ctx, char **body, const edg_wll_JobStat *toAdd, const char *tag, const char *UNUSED_subTag, const int null)
+{
+ char *pomA, *pomB, *newBody;
+ char **list = NULL;
+ int i = 0, len, tot_len = 0;
+ int *len_list = NULL;
+
+
+ while (toAdd[i].state != null) {
+ edg_wll_JobStatusToXML(ctx, toAdd[i], &pomA);
+ len = strlen(pomA);
+
+ i++;
+ tot_len += len;
+
+ list = (char **) realloc(list, i * sizeof(*list));
+ list[i-1] = pomA;
+ pomA = NULL;
+ len_list = (int *) realloc(len_list, i * sizeof(*len_list));
+ len_list[i-1] = len;
+ }
+
+ /* list termination */
+ list = (char **) realloc(list, (i+1) * sizeof(*list));
+ list[i] = NULL;
+
+ /* glueing all list fields together & freeing the list */
+ pomA = (char *) malloc(tot_len * sizeof(char) + 1);
+ pomB = pomA;
+
+ i = 0;
+ while (list[i]) {
+ memcpy(pomB, list[i], len_list[i] );
+ pomB += len_list[i];
+
+ /* freeing the list */
+ free(list[i]);
+
+ i++;
+ }
+ *pomB = '\0';
+ free(list);
+ free(len_list);
+
+ asprintf(&newBody,"%s\t\t\t<%s>\r\n%s\t\t\t</%s>\r\n", *body, tag, pomA, tag);
+ free(*body);
+ free(pomA);
+ *body = newBody;
+}
+
+
+
+/* construct Message-Body of Response-Line for edg_wll_JobStatus */
+int edg_wll_JobStatusToXML(edg_wll_Context ctx, edg_wll_JobStat stat, char **message)
+{
+ char *pomA, *pomB, *pomC;
+
+
+ pomB = strdup("");
+
+@@@{
+ selectType $status '_common_';
+ for (getFieldsOrdered $status) {
+ my $f = selectField $status $_;
+ next if defined($f->{special}) && $f->{special} eq 'XMLstructured';
+ my $ft = $f->{type};
+ my $n = $f->{null};
+ gen "edg_wll_add_$ft\_to_XMLBody(&pomB, stat.$_, \"$_\", $n);\n";
+ }
+@@@}
+ if (stat.children) edg_wll_add_strlist_to_XMLBody(&pomB, stat.children, "children", "jobId", "\t\t\t", NULL);
+ if (stat.children_hist) edg_wll_add_intlist_to_XMLBody(&pomB, stat.children_hist, "children_hist", edg_wll_StatToString, "\t\t\t", 1, stat.children_hist[0]);
+ if (stat.children_states) edg_wll_add_stslist_to_XMLBody(ctx, &pomB, stat.children_states, "children_states", "", EDG_WLL_JOB_UNDEF);
+ if (stat.user_tags) edg_wll_add_taglist_to_XMLBody(&pomB, stat.user_tags, "user_tags", "tag", "name", "\t\t\t", NULL);
+ if (stat.stateEnterTimes) edg_wll_add_intlist_to_XMLBody(&pomB, stat.stateEnterTimes, "stateEnterTimes", edg_wll_StatToString, "\t\t\t",1, stat.stateEnterTimes[0]);
+
+ pomC = edg_wll_StatToString(stat.state);
+
+ if (ctx->errDesc || ctx->errCode)
+ trio_asprintf(&pomA,"<jobStat name=\"%|Xs\" code=\"%d\" desc=\"%|Xs\">\r\n%s</jobStat>",
+ pomC, ctx->errCode,ctx->errDesc, pomB);
+ else
+ trio_asprintf(&pomA,"<jobStat name=\"%|Xs\">\r\n%s</jobStat>",
+ pomC, pomB);
+
+ free(pomB);
+ free(pomC);
+
+ *message = pomA;
+
+ return 0;
+}
+
+
+
+/* construct Message-Body of Request-Line for edg_wll_Purge */
+int edg_wll_PurgeResultToXML(
+ edg_wll_Context ctx,
+ edg_wll_PurgeResult *result,
+ char **message)
+{
+ char *pomA, *pomB;
+
+
+ if (!result) { *message = NULL; return(-1); }
+
+ pomA = strdup("");
+ edg_wll_add_strlist_to_XMLBody(&pomA, result->jobs, "jobs", "jobId", "\t", NULL);
+ edg_wll_add_string_to_XMLBody(&pomA, result->server_file, "server_file", NULL);
+
+ if (ctx->errDesc || ctx->errCode)
+ trio_asprintf(&pomB,"%s code=\"%d\" desc=\"%|Xs\">\r\n%s%s",
+ PURGE_RESULT_BEGIN, ctx->errCode, ctx->errDesc, pomA, PURGE_RESULT_END);
+ else
+ trio_asprintf(&pomB,"%s>\r\n%s%s", PURGE_RESULT_BEGIN, pomA, PURGE_RESULT_END);
+ free(pomA);
+
+ *message = pomB;
+ return 0;
+}
+
+
+
+/* construct Message-Body of Request-Line for edg_wll_Dump */
+int edg_wll_DumpResultToXML(
+ edg_wll_Context ctx,
+ edg_wll_DumpResult *result,
+ char **message)
+{
+ char *pomA, *pomB;
+
+
+ if (!result) { *message = NULL; return(-1); }
+
+ pomA = strdup("");
+ edg_wll_add_string_to_XMLBody(&pomA, result->server_file, "server_file", NULL);
+ if (result->from < 0)
+ edg_wll_add_string_to_XMLBody(&pomA,
+ edg_wll_DumpConstToString(result->from), "from", NULL);
+ else
+ edg_wll_add_time_t_to_XMLBody(&pomA, result->from, "from", 0);
+ if (result->to < 0)
+ edg_wll_add_string_to_XMLBody(&pomA,
+ edg_wll_DumpConstToString(result->to), "to", NULL);
+ else
+ edg_wll_add_time_t_to_XMLBody(&pomA, result->to, "to", 0);
+
+ if (ctx->errDesc || ctx->errCode)
+ trio_asprintf(&pomB,"%s code=\"%d\" desc=\"%|Xs\">\r\n%s%s",
+ DUMP_RESULT_BEGIN, ctx->errCode, ctx->errDesc, pomA, DUMP_RESULT_END);
+ else
+ trio_asprintf(&pomB,"%s>\r\n%s%s", DUMP_RESULT_BEGIN, pomA, DUMP_RESULT_END);
+ free(pomA);
+
+ *message = pomB;
+ return 0;
+}
+
+
+/* construct Message-Body of Request-Line for edg_wll_Load */
+int edg_wll_LoadResultToXML(
+ edg_wll_Context ctx,
+ edg_wll_LoadResult *result,
+ char **message)
+{
+ char *pomA, *pomB;
+
+
+ if (!result) { *message = NULL; return(-1); }
+
+ pomA = strdup("");
+ edg_wll_add_string_to_XMLBody(&pomA, result->server_file, "server_file", NULL);
+ edg_wll_add_time_t_to_XMLBody(&pomA, result->from, "from", 0);
+ edg_wll_add_time_t_to_XMLBody(&pomA, result->to, "to", 0);
+
+ if (ctx->errDesc || ctx->errCode)
+ trio_asprintf(&pomB,"%s code=\"%d\" desc=\"%|Xs\">\r\n%s%s",
+ LOAD_RESULT_BEGIN, ctx->errCode, ctx->errDesc, pomA, LOAD_RESULT_END);
+ else
+ trio_asprintf(&pomB,"%s>\r\n%s%s", LOAD_RESULT_BEGIN, pomA, LOAD_RESULT_END);
+ free(pomA);
+
+ *message = pomB;
+ return 0;
+}
+
+
+/* construct Message-Body of Request-Line for edg_wll_GetIndexedAttrs */
+int edg_wll_IndexedAttrsToXML(
+ edg_wll_Context ctx,
+ char **message)
+{
+ int i,j;
+ char *pomA, *pomB;
+
+ pomA = strdup("");
+ if (ctx->job_index) {
+ for (i=0; ctx->job_index[i]; i++) {
+ asprintf(&pomB, "%s\t%s\r\n",pomA,"<index>");
+ free(pomA);
+ pomA = pomB;
+
+ for (j=0; ctx->job_index[i][j].attr != EDG_WLL_QUERY_ATTR_UNDEF; j++) {
+ asprintf(&pomB, "%s\t\t%s\r\n",pomA,"<QueryRec>");
+ free(pomA);
+ pomA = pomB;
+
+ edg_wll_add_string_to_XMLBody(&pomA,
+ edg_wll_query_attrToString(ctx->job_index[i][j].attr),
+ "attribute", NULL);
+
+ if (ctx->job_index[i][j].attr == EDG_WLL_QUERY_ATTR_TIME)
+ edg_wll_add_string_to_XMLBody(&pomA,
+ edg_wll_StatToString(ctx->job_index[i][j].attr_id.state),
+ "state", NULL);
+
+ if (ctx->job_index[i][j].attr == EDG_WLL_QUERY_ATTR_USERTAG)
+ edg_wll_add_string_to_XMLBody(&pomA,
+ ctx->job_index[i][j].attr_id.tag,
+ "name", NULL);
+
+ asprintf(&pomB, "%s\t\t%s\r\n",pomA,"</QueryRec>");
+ free(pomA);
+ pomA = pomB;
+ }
+
+ asprintf(&pomB, "%s\t%s\r\n",pomA,"</index>");
+ free(pomA);
+ pomA = pomB;
+ }
+ }
+
+ if (ctx->errDesc || ctx->errCode)
+ trio_asprintf(&pomB,"%s code=\"%d\" desc=\"%|Xs\">\r\n%s%s",
+ INDEXED_ATTRS_BEGIN, ctx->errCode, ctx->errDesc, pomA, INDEXED_ATTRS_END);
+ else
+ trio_asprintf(&pomB,"%s>\r\n%s%s", INDEXED_ATTRS_BEGIN, pomA, INDEXED_ATTRS_END);
+ free(pomA);
+
+
+ *message = pomB;
+ return 0;
+}
+
+
+
+/* construct Message-Body of Request-Line for edg_wll_Notif */
+int edg_wll_NotifResultToXML(
+ edg_wll_Context ctx,
+ time_t validity,
+ char **message)
+{
+ char *pomA, *pomB;
+
+
+ pomA = strdup("");
+ edg_wll_add_time_t_to_XMLBody(&pomA, validity, "validity", -1);
+
+ if (ctx->errDesc || ctx->errCode)
+ trio_asprintf(&pomB,"%s code=\"%d\" desc=\"%|Xs\">\r\n%s%s",
+ NOTIF_RESULT_BEGIN, ctx->errCode, ctx->errDesc, pomA, NOTIF_RESULT_END);
+ else
+ trio_asprintf(&pomB,"%s>\r\n%s%s", NOTIF_RESULT_BEGIN, pomA, NOTIF_RESULT_END);
+ free(pomA);
+
+ *message = pomB;
+ return 0;
+}
+
+
--- /dev/null
+#ifndef _LB_XML_PARSE_H
+#define _LB_XML_PARSE_H
+
+#ident "$Header$"
+
+#include "glite/lb/consumer.h"
+#include "glite/lb/notification.h"
+#include "glite/lb/purge.h"
+#include "glite/lb/dump.h"
+#include "glite/lb/load.h"
+
+/* function for parsing/unparsing XML requests from client */
+
+int parseJobQueryRec(edg_wll_Context ctx, const char *messageBody, long len, edg_wll_QueryRec ***conditions);
+int parseQueryJobsRequest(edg_wll_Context ctx, char *messageBody, edg_wll_QueryRec ***conditions, int *flags);
+int parseQueryEventsRequest(edg_wll_Context ctx, char *messageBody, edg_wll_QueryRec ***job_conditions, edg_wll_QueryRec ***event_conditions);
+int parsePurgeRequest(edg_wll_Context ctx, char *messageBody, int (*tagToIndex)(), edg_wll_PurgeRequest *request);
+int parseDumpRequest(edg_wll_Context ctx, char *messageBody, edg_wll_DumpRequest *request);
+int parseLoadRequest(edg_wll_Context ctx, char *messageBody, edg_wll_LoadRequest *request);
+int parseNotifRequest(edg_wll_Context ctx, char *messageBody, char **function, edg_wll_NotifId *notifId, char **address, edg_wll_NotifChangeOp *op, edg_wll_QueryRec ***conditions);
+int edg_wll_QueryEventsToXML(edg_wll_Context, edg_wll_Event *, char **);
+int edg_wll_QueryJobsToXML(edg_wll_Context, edg_wlc_JobId *, edg_wll_JobStat *, char **);
+int edg_wll_JobStatusToXML(edg_wll_Context, edg_wll_JobStat, char **);
+int edg_wll_UserJobsToXML(edg_wll_Context, edg_wlc_JobId *, char **);
+int edg_wll_PurgeResultToXML(edg_wll_Context ctx, edg_wll_PurgeResult *result, char **message);
+int edg_wll_DumpResultToXML(edg_wll_Context ctx, edg_wll_DumpResult *result, char **message);
+int edg_wll_LoadResultToXML(edg_wll_Context ctx, edg_wll_LoadResult *result, char **message);
+int edg_wll_IndexedAttrsToXML(edg_wll_Context ctx, char **message);
+int edg_wll_NotifResultToXML(edg_wll_Context ctx, time_t validity, char **message);
+void edg_wll_ErrorToXML(edg_wll_Context, char **);
+
+#endif
--- /dev/null
+#ident "$Header$"
+
+#include "mysql/mysql.h" // MySql header file
+#include "mysql/mysqld_error.h"
+#include "mysql/errmsg.h"
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <time.h>
+
+#include "lbs_db.h"
+#include "glite/lb/context-int.h"
+
+
+#define DEFAULTCS "lbserver/@localhost:lbserver20"
+
+#define my_err() edg_wll_SetError(ctx,EDG_WLL_ERROR_DB_CALL,mysql_error((MYSQL *) ctx->mysql))
+
+struct _edg_wll_Stmt {
+ MYSQL_RES *result;
+ edg_wll_Context ctx;
+};
+
+edg_wll_ErrorCode edg_wll_DBConnect(edg_wll_Context ctx,char *cs)
+{
+ char *buf = NULL;
+ char *host,*user,*pw,*db;
+ char *slash,*at,*colon;
+
+ if (!cs) cs = DEFAULTCS;
+
+ if (!(ctx->mysql = (void *) mysql_init(NULL)))
+ return edg_wll_SetError(ctx,ENOMEM,NULL);
+
+ host = user = pw = db = NULL;
+
+ buf = strdup(cs);
+ slash = strchr(buf,'/');
+ at = strrchr(buf,'@');
+ colon = strrchr(buf,':');
+
+ if (!slash || !at || !colon) {
+ free(buf);
+ return edg_wll_SetError(ctx,EINVAL,"DB connect string");
+ }
+
+ *slash = *at = *colon = 0;
+ host = at+1;
+ user = buf;
+ pw = slash+1;
+ db = colon+1;
+
+ if (!mysql_real_connect((MYSQL *) ctx->mysql,host,user,pw,db,0,NULL,0)) {
+ free(buf);
+ return my_err();
+ }
+
+ free(buf);
+ return edg_wll_ResetError(ctx);
+}
+
+void edg_wll_DBClose(edg_wll_Context ctx)
+{
+ mysql_close((MYSQL *) ctx->mysql);
+ ctx->mysql = NULL;
+}
+
+int edg_wll_ExecStmt(edg_wll_Context ctx,char *txt,edg_wll_Stmt *stmt)
+{
+ int err;
+ int retry_nr = 0;
+ int do_reconnect = 0;
+
+ edg_wll_ResetError(ctx);
+
+ if (stmt) {
+ *stmt = NULL;
+ }
+
+ while (retry_nr == 0 || do_reconnect) {
+ do_reconnect = 0;
+ if (mysql_query((MYSQL *) ctx->mysql,txt)) {
+ /* error occured */
+ switch (err = mysql_errno((MYSQL *) ctx->mysql)) {
+ case 0:
+ break;
+ case ER_DUP_ENTRY:
+ edg_wll_SetError(ctx,EEXIST,mysql_error((MYSQL *) ctx->mysql));
+ return -1;
+ break;
+ case CR_SERVER_LOST:
+ if (retry_nr <= 0)
+ do_reconnect = 1;
+ break;
+ default:
+ my_err();
+ return -1;
+ break;
+ }
+ }
+ retry_nr++;
+ }
+
+ if (stmt) {
+ *stmt = malloc(sizeof(**stmt));
+ if (!*stmt) {
+ edg_wll_SetError(ctx,ENOMEM,NULL);
+ return -1;
+ }
+ memset(*stmt,0,sizeof(**stmt));
+ (**stmt).ctx = ctx;
+ (**stmt).result = mysql_store_result((MYSQL *) ctx->mysql);
+ if (!(**stmt).result) {
+ if (mysql_errno((MYSQL *) ctx->mysql)) {
+ my_err();
+ return -1;
+ }
+ }
+ } else {
+ MYSQL_RES *r = mysql_store_result((MYSQL *) ctx->mysql);
+ mysql_free_result(r);
+ }
+
+ return mysql_affected_rows((MYSQL *) ctx->mysql);
+}
+
+int edg_wll_FetchRow(edg_wll_Stmt stmt,char **res)
+{
+ MYSQL_ROW row;
+ edg_wll_Context ctx = stmt->ctx;
+ int nr,i;
+ unsigned long *len;
+
+ edg_wll_ResetError(ctx);
+
+ if (!stmt->result) return 0;
+
+ if (!(row = mysql_fetch_row(stmt->result))) {
+ if (mysql_errno((MYSQL *) ctx->mysql)) {
+ my_err();
+ return -1;
+ } else return 0;
+ }
+
+ nr = mysql_num_fields(stmt->result);
+ len = mysql_fetch_lengths(stmt->result);
+ for (i=0; i<nr; i++) res[i] = len[i] ? strdup(row[i]) : strdup("");
+
+ return nr;
+}
+
+int edg_wll_QueryColumns(edg_wll_Stmt stmt,char **cols)
+{
+ int i = 0;
+ MYSQL_FIELD *f;
+
+ while ((f = mysql_fetch_field(stmt->result))) cols[i++] = f->name;
+ return i == 0;
+}
+
+void edg_wll_FreeStmt(edg_wll_Stmt *stmt)
+{
+ if (*stmt) {
+ if ((**stmt).result) mysql_free_result((**stmt).result);
+ free(*stmt);
+ *stmt = NULL;
+ }
+}
+
+
+char *edg_wll_TimeToDB(time_t t)
+{
+ struct tm *tm = gmtime(&t);
+ char tbuf[256];
+
+ sprintf(tbuf,"'%4d-%02d-%02d %02d:%02d:%02d'",tm->tm_year+1900,tm->tm_mon+1,
+ tm->tm_mday,tm->tm_hour,tm->tm_min,tm->tm_sec);
+
+ return strdup(tbuf);
+}
+
+time_t edg_wll_DBToTime(char *t)
+{
+ struct tm tm;
+
+ memset(&tm,0,sizeof(tm));
+ setenv("TZ","UTC",1); tzset();
+ sscanf(t,"%4d-%02d-%02d %02d:%02d:%02d",
+ &tm.tm_year,&tm.tm_mon,&tm.tm_mday,
+ &tm.tm_hour,&tm.tm_min,&tm.tm_sec);
+ tm.tm_year -= 1900;
+ tm.tm_mon--;
+
+ return mktime(&tm);
+}
+
+int edg_wll_DBCheckVersion(edg_wll_Context ctx)
+{
+ MYSQL *m = (MYSQL *) ctx->mysql;
+ const char *ver_s = mysql_get_server_info(m);
+ int major,minor,sub,version;
+
+ if (!ver_s || 3 != sscanf(ver_s,"%d.%d.%d",&major,&minor,&sub))
+ return edg_wll_SetError(ctx,EINVAL,"retreiving MySQL version");
+
+ version = 10000*major + 100*minor + sub;
+
+ if (version < EDG_WLL_MYSQL_VERSION) {
+ char msg[300];
+
+ snprintf(msg,sizeof msg,"Your MySQL version is %d. At least %d required.",version,EDG_WLL_MYSQL_VERSION);
+ return edg_wll_SetError(ctx,EINVAL,msg);
+ }
+
+ return edg_wll_ResetError(ctx);
+}
--- /dev/null
+#ifndef _LBS_DB_H
+#define _LBS_DB_H
+
+#ident "$Header$"
+
+#include <sys/types.h>
+#include <sys/time.h>
+
+#include "glite/lb/consumer.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define EDG_WLL_MYSQL_VERSION 40001
+
+typedef struct _edg_wll_Stmt *edg_wll_Stmt;
+
+edg_wll_ErrorCode edg_wll_DBConnect(
+ edg_wll_Context, /* INOUT: */
+ char * /* IN: connect string user/password@host:database */
+);
+
+void edg_wll_DBClose(edg_wll_Context);
+
+
+/* Parse and execute SQL statement. Returns number of rows selected, created
+ * or affected by update, or -1 on error */
+
+int edg_wll_ExecStmt(
+ edg_wll_Context, /* INOUT: */
+ char *, /* IN: SQL statement */
+ edg_wll_Stmt * /* OUT: statement handle. Usable for select only */
+);
+
+
+/* Fetch next row of select statement.
+ * All columns are returned as fresh allocated strings
+ *
+ * return values:
+ * >0 - number of fields of the retrieved row
+ * 0 - no more rows
+ * -1 - error
+ *
+ * Errors are stored in context passed to previous edg_wll_ExecStmt() */
+
+int edg_wll_FetchRow(
+ edg_wll_Stmt, /* IN: statement */
+ char ** /* OUT: array of fetched values.
+ * As number of columns is fixed and known,
+ * expects allocated array of pointers here */
+);
+
+/* Retrieve column names of a query statement */
+
+int edg_wll_QueryColumns(
+ edg_wll_Stmt, /* IN: statement */
+ char ** /* OUT: result set column names. Expects allocated array. */
+);
+
+/* Free the statement structure */
+
+void edg_wll_FreeStmt(
+ edg_wll_Stmt * /* INOUT: statement */
+);
+
+
+/* convert time_t into database-specific time string
+ * returns pointer to static area that is changed by subsequent calls */
+char *edg_wll_TimeToDB(time_t);
+time_t edg_wll_DBToTime(char *);
+
+extern edg_wll_ErrorCode edg_wll_Open(edg_wll_Context ctx, char *cs);
+
+/**
+ * Check database version.
+ */
+int edg_wll_DBCheckVersion(edg_wll_Context);
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
--- /dev/null
+#ident "$Header$"
+
+#include <time.h>
+#include <stdio.h>
+#include <string.h>
+#include <syslog.h>
+#include <assert.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <ctype.h>
+
+#include "glite/lb/trio.h"
+
+#include "glite/lb/context-int.h"
+#include "glite/lb/events_parse.h"
+#include "glite/lb/ulm_parse.h"
+#include "glite/lb/purge.h"
+#include "glite/lb/purge.h"
+#include "glite/lb/events.h"
+#include "glite/lb/dump.h"
+#include "glite/lb/load.h"
+
+#include "store.h"
+#include "purge.h"
+#include "lbs_db.h"
+#include "query.h"
+#include "get_events.h"
+#include "server_state.h"
+
+
+static int read_line(char **buff, int fd);
+
+int edg_wll_LoadEvents(edg_wll_Context ctx,const edg_wll_LoadRequest *req,edg_wll_LoadResult *result)
+{
+ int fd,
+ reject_fd = -1,
+ readret, i;
+ char *line = NULL,
+ buff[30];
+ edg_wll_Event *event;
+ edg_wlc_JobId jobid = NULL;
+
+
+ edg_wll_ResetError(ctx);
+
+ if ( !req->server_file )
+ return edg_wll_SetError(ctx, EINVAL, "Server file is not specified for load");
+
+ if ( (fd = open(req->server_file, O_RDONLY)) == -1 )
+ return edg_wll_SetError(ctx, errno, "Server can not open the file");
+
+ memset(result,0,sizeof(*result));
+ i = 0;
+ while ( 1 )
+ {
+ /* Read one line
+ */
+ if ( (readret = read_line(&line, fd)) == -1 )
+ return edg_wll_SetError(ctx, errno, "reading dump file");
+
+ if ( readret == 0 )
+ break;
+
+ i++;
+ if ( sscanf(line, "DG.ARRIVED=%s %*s", buff) != 1
+ || edg_wll_ParseEvent(ctx, line, &event) )
+ {
+ char errs[100];
+ sprintf(errs, "Error parsing event at line %d", i);
+ if ( !edg_wll_Error(ctx,NULL,NULL) )
+ edg_wll_SetError(ctx, EINVAL, errs);
+ fprintf(stderr, errs);
+ continue;
+ }
+ edg_wll_ULMDateToTimeval(buff, &(event->any.arrived));
+
+ if ( i == 1 )
+ {
+ result->from = event->any.arrived.tv_sec;
+ result->to = event->any.arrived.tv_sec;
+ }
+ ctx->event_load = 1;
+ if ( edg_wll_StoreEvent(ctx, event, NULL) )
+ {
+ int len = strlen(line),
+ total = 0,
+ written;
+
+ fprintf(stderr, "Can't store event\n");
+ if ( reject_fd == -1 )
+ {
+ char *s, *s1;
+
+ if ( result->server_file != NULL )
+ goto cycle_clean;
+
+ s1 = strdup(req->server_file);
+ s = strrchr(s1, '/');
+ if ( s )
+ {
+ *s = '\0';
+ reject_fd = edg_wll_CreateFileStorage(ctx,FILE_TYPE_LOAD,s1,&(result->server_file));
+ }
+ else
+ reject_fd = edg_wll_CreateFileStorage(ctx,FILE_TYPE_LOAD,NULL,&(result->server_file));
+ if ( reject_fd == -1 )
+ goto cycle_clean;
+ printf("New reject file %s created\n", result->server_file);
+ free(s1);
+ }
+ /* Save the line into "reject_file"
+ */
+ while (total != len) {
+ written = write(reject_fd, line+total, len-total);
+ if (written < 0 && errno != EAGAIN) {
+ edg_wll_SetError(ctx, errno, "writing load reject file");
+ free(line);
+ break;
+ }
+ total += written;
+ }
+ write(reject_fd,"\n",1);
+ }
+ else
+ {
+ result->to = event->any.arrived.tv_sec;
+ if ( jobid )
+ {
+ char *md5_jobid = edg_wlc_JobIdGetUnique(jobid);
+
+ if ( strcmp(md5_jobid, edg_wlc_JobIdGetUnique(event->any.jobId)) )
+ {
+ edg_wll_JobStat st;
+
+ edg_wll_JobStatus(ctx, jobid, 0, &st);
+ edg_wll_FreeStatus(&st);
+
+ edg_wlc_JobIdFree(jobid);
+ edg_wlc_JobIdDup(event->any.jobId, &jobid);
+ }
+ free(md5_jobid);
+ }
+ else
+ edg_wlc_JobIdDup(event->any.jobId, &jobid);
+ }
+
+
+cycle_clean:
+ ctx->event_load = 0;
+ edg_wll_FreeEvent(event);
+ }
+
+ if ( jobid )
+ {
+ edg_wll_JobStat st;
+
+ edg_wll_JobStatus(ctx, jobid, 0, &st);
+ edg_wll_FreeStatus(&st);
+ edg_wlc_JobIdFree(jobid);
+ }
+
+ if ( reject_fd != -1 )
+ close(reject_fd);
+
+ return edg_wll_Error(ctx,NULL,NULL);
+}
+
+#define BUFFSZ 1024
+
+static int read_line(char **buff, int fd)
+{
+ int ct, i;
+
+
+ if ( *buff == NULL )
+ {
+ *buff = malloc(BUFFSZ);
+ if ( *buff == NULL )
+ return -1;
+ }
+
+ i = 0;
+ while ( 1 )
+ {
+ if ( (ct = read(fd, (*buff)+i, 1)) == -1 )
+ return -1;
+
+ if ( ct == 0 )
+ return 0;
+
+ if ( (*buff)[i] == '\n' )
+ {
+ (*buff)[i--] = '\0';
+ while ( (i != -1) && isspace((*buff)[i]) ) i--;
+ if ( i == -1 )
+ {
+ /** empty line
+ */
+ i = 0;
+ continue;
+ }
+ else
+ return 1;
+ }
+
+ i++;
+ }
+}
--- /dev/null
+#include <unistd.h>
+#include <sys/ipc.h>
+#include <sys/sem.h>
+#include <errno.h>
+
+#include "glite/wms/jobid/cjobid.h"
+#include "glite/lb/context-int.h"
+#include "lock.h"
+
+
+int edg_wll_LockUnlockJob(const edg_wll_Context ctx,const edg_wlc_JobId job,int lock)
+{
+ struct sembuf s;
+ char *un = edg_wlc_JobIdGetUnique(job);
+ int n,i;
+ static const char b64[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_";
+
+ if (!un) return edg_wll_SetError(ctx,EINVAL,"jobid");
+
+ for (n=0; n<sizeof b64 && b64[n] != un[0]; n++);
+ for (i=0; i<sizeof b64 && b64[i] != un[1]; i++);
+ n += i<<6;
+
+ fprintf(stderr,"[%d] semop(%d,%d) \n",getpid(),n % ctx->semaphores,lock);
+
+ s.sem_num = n % ctx->semaphores;
+ s.sem_op = lock;
+ s.sem_flg = SEM_UNDO;
+
+ if (semop(ctx->semset,&s,1)) return edg_wll_SetError(ctx,errno,"edg_wll_LockUnlockJob()");
+ return edg_wll_ResetError(ctx);
+}
--- /dev/null
+#define edg_wll_LockJob(ctx,job) edg_wll_LockUnlockJob((ctx),(job),-1)
+#define edg_wll_UnlockJob(ctx,job) edg_wll_LockUnlockJob((ctx),(job),1)
+
+int edg_wll_LockUnlockJob(const edg_wll_Context,const edg_wlc_JobId,int);
--- /dev/null
+#ident "$Header$"
+
+#include <string.h>
+#include <time.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <syslog.h>
+
+#include "glite/lb/producer.h"
+#include "glite/lb/consumer.h"
+#include "glite/lb/context.h"
+#include "glite/lb/trio.h"
+
+#include "lbs_db.h"
+#include "lb_authz.h"
+#include "lb_xml_parse.h"
+#include "query.h"
+#include "il_notification.h"
+
+
+
+static int notif_match_conditions(edg_wll_Context,const edg_wll_JobStat *,const char *);
+static int notif_check_acl(edg_wll_Context,const edg_wll_JobStat *,const char *);
+
+int edg_wll_NotifExpired(edg_wll_Context,const char *);
+
+int edg_wll_NotifMatch(edg_wll_Context ctx, const edg_wll_JobStat *stat)
+{
+ edg_wll_NotifId nid = NULL;
+ char *jobq,*ju = NULL,*jobc[5];
+ edg_wll_Stmt jobs = NULL;
+ int ret,i;
+ time_t now = time(NULL);
+
+ edg_wll_ResetError(ctx);
+
+ if ( (ret = edg_wll_NotifIdCreate(ctx->srvName, ctx->srvPort, &nid)) )
+ {
+ edg_wll_SetError(ctx, ret, "edg_wll_NotifMatch()");
+ goto err;
+ }
+ trio_asprintf(&jobq,
+ "select distinct n.notifid,n.destination,n.valid,u.cert_subj,n.conditions "
+ "from notif_jobs j,users u,notif_registrations n "
+ "where j.notifid=n.notifid and n.userid=u.userid "
+ " and j.jobid = '%|Ss'",ju = edg_wlc_JobIdGetUnique(stat->jobId));
+
+ free(ju);
+
+ if (edg_wll_ExecStmt(ctx,jobq,&jobs) < 0) goto err;
+
+ while ((ret = edg_wll_FetchRow(jobs,jobc)) > 0) {
+ if (now > edg_wll_DBToTime(jobc[2]))
+ edg_wll_NotifExpired(ctx,jobc[0]);
+ else if (notif_match_conditions(ctx,stat,jobc[4]) &&
+ notif_check_acl(ctx,stat,jobc[3]))
+ {
+ char *dest, *aux;
+ int port;
+
+ fprintf(stderr,"NOTIFY: %s, job %s\n",jobc[0],
+ ju = edg_wlc_JobIdGetUnique(stat->jobId));
+ free(ju);
+
+ dest = strdup(jobc[1]);
+ if ( !(aux = strchr(dest, ':')) )
+ {
+ edg_wll_SetError(ctx, EINVAL, "Can't parse notification destination");
+ free(dest);
+ for (i=0; i<sizeof(jobc)/sizeof(jobc[0]); i++) free(jobc[i]);
+ goto err;
+ }
+ *aux = 0;
+ aux++;
+ port = atoi(aux);
+
+ if ( edg_wll_NotifIdSetUnique(&nid, jobc[0]) )
+ {
+ free(dest);
+ goto err;
+ }
+ /* XXX: only temporary hack!!!
+ */
+ ctx->p_instance = strdup("");
+ if ( edg_wll_NotifJobStatus(ctx, nid, dest, port, jobc[3], *stat) )
+ {
+ free(dest);
+ for (i=0; i<sizeof(jobc)/sizeof(jobc[0]); i++) free(jobc[i]);
+ goto err;
+ }
+ free(dest);
+ }
+
+ for (i=0; i<sizeof(jobc)/sizeof(jobc[0]); i++) free(jobc[i]);
+ }
+ if (ret < 0) goto err;
+
+err:
+ if ( nid ) edg_wll_NotifIdFree(nid);
+ free(jobq);
+ edg_wll_FreeStmt(&jobs);
+ return edg_wll_Error(ctx,NULL,NULL);
+}
+
+int edg_wll_NotifExpired(edg_wll_Context ctx,const char *notif)
+{
+ /* TODO */
+ return 0;
+}
+
+
+static int notif_match_conditions(edg_wll_Context ctx,const edg_wll_JobStat *stat,const char *cond)
+{
+ edg_wll_QueryRec **c,**p;
+ int match,i;
+
+ if (!cond) return 1;
+
+ if (parseJobQueryRec(ctx,cond,strlen(cond),&c)) {
+ fputs("notif_match_conditions(): parseJobQueryRec failed\n",stderr);
+ syslog(LOG_ERR,"notif_match_conditions(): parseJobQueryRec failed");
+ return 1;
+ }
+
+ match = match_status(ctx,stat,(const edg_wll_QueryRec **) c);
+ if ( c )
+ {
+ for (p = c; *p; p++) {
+ for (i=0; (*p)[i].attr; i++)
+ edg_wll_QueryRecFree((*p)+i);
+ free(*p);
+ }
+ free(c);
+ }
+ return match;
+}
+
+/* FIXME: does not favour any VOMS information in ACL
+ * effective VOMS groups of the recipient are not available here, should be
+ * probably stored along with the registration.
+ */
+static int notif_check_acl(edg_wll_Context ctx,const edg_wll_JobStat *stat,const char *recip)
+{
+ edg_wll_Acl acl = calloc(1,sizeof *acl);
+ GACLacl *gacl;
+ int ret;
+
+ edg_wll_ResetError(ctx);
+ if (ctx->noAuth || strcmp(stat->owner,recip) == 0) return 1;
+
+ ret = edg_wll_DecodeACL(stat->acl,&gacl);
+ if (ret) {
+ edg_wll_SetError(ctx,EINVAL,"decoding ACL");
+ return 0;
+ }
+
+ acl->string = stat->acl;
+ acl->value = gacl;
+
+ ret = edg_wll_CheckACL(ctx, acl, EDG_WLL_PERM_READ);
+
+ acl->string = NULL;
+ edg_wll_FreeAcl(acl);
+
+ return !ret;
+}
--- /dev/null
+#include <string.h>
+#include <time.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+#include "glite/wms/jobid/strmd5.h"
+#include "glite/lb/trio.h"
+#include "glite/lb/context-int.h"
+#include "glite/lb/xml_parse.h"
+#include "glite/lb/notification.h"
+#include "lbs_db.h"
+
+
+static char *get_user(edg_wll_Context ctx, int create);
+static int update_notif(edg_wll_Context, const edg_wll_NotifId,
+ const char *, const char *, const char *);
+
+int edg_wll_NotifNewServer(
+ edg_wll_Context ctx,
+ edg_wll_QueryRec const * const *conditions,
+ char const *address_override,
+ const edg_wll_NotifId nid,
+ time_t *valid)
+{
+ int i, j,
+ ct,
+ new_rows;
+ char *q = NULL,
+ *nid_s = NULL,
+ *time_s = NULL,
+ *addr_s = NULL,
+ *xml_conds = NULL,
+ *owner = NULL,
+ **jobs = NULL;
+ edg_wll_QueryRec **nconds = NULL;
+
+
+ /* Format notification ID
+ */
+ if ( !(nid_s = edg_wll_NotifIdGetUnique(nid)) )
+ goto cleanup;
+
+ /* Get notification owner
+ */
+ if ( !(owner = get_user(ctx, 1)) )
+ goto cleanup;
+
+ /* Format conditions
+ * - first of all separate all jobids
+ * - then format new condition list without jobids and encode it into an XML string
+ */
+ if ( !conditions || !conditions[0] )
+ {
+ edg_wll_SetError(ctx, EINVAL, "Empty condition list");
+ goto cleanup;
+ }
+ for ( new_rows = ct = i = 0; conditions[i]; i++ )
+ {
+ if ( conditions[i][0].attr && conditions[i][0].attr != EDG_WLL_QUERY_ATTR_JOBID )
+ new_rows++;
+ for ( j = 0; conditions[i][j].attr; j++ )
+ if ( conditions[i][j].attr == EDG_WLL_QUERY_ATTR_JOBID )
+ ct++;
+ }
+ if ( !ct )
+ {
+ edg_wll_SetError(ctx, EINVAL, "Notification has to bind to at least one jobID");
+ goto cleanup;
+ }
+ if ( !(jobs = calloc(ct+1, sizeof(char *)))
+ || !(nconds = calloc(new_rows+1, sizeof(edg_wll_QueryRec *))) )
+ {
+ edg_wll_SetError(ctx, errno, NULL);
+ goto cleanup;
+ }
+ for ( ct = i = 0; conditions[i]; i++ )
+ for ( j = 0; conditions[i][j].attr; j++ )
+ if ( conditions[i][j].attr == EDG_WLL_QUERY_ATTR_JOBID )
+ if ( !(jobs[ct++] = edg_wlc_JobIdGetUnique(conditions[i][j].value.j)) )
+ {
+ edg_wll_SetError(ctx, errno, NULL);
+ goto cleanup;
+ }
+ for ( new_rows = i = 0; conditions[i]; i++ )
+ if ( conditions[i][0].attr && conditions[i][0].attr != EDG_WLL_QUERY_ATTR_JOBID )
+ /* !!! DO NOT DEALLOCATE this arrays (it is not neccessary to allocate new
+ * mem - it's used only once and only for xml parsing
+ */
+ nconds[new_rows++] = (edg_wll_QueryRec *) (conditions[i]);
+ if ( edg_wll_JobQueryRecToXML(ctx, (edg_wll_QueryRec const * const *) nconds, &xml_conds) )
+ {
+ /* XXX: edg_wll_JobQueryRecToXML() do not set errors in context!
+ * can't get propper error number :(
+ */
+ edg_wll_SetError(ctx, errno, "Can't encode data into xml");
+ goto cleanup;
+ }
+
+ /* Format time of validity
+ */
+ *valid = time(NULL);
+ if ( ctx->peerProxyValidity
+ && (ctx->peerProxyValidity - *valid) < ctx->notifDuration )
+ *valid = ctx->peerProxyValidity;
+ else
+ *valid += ctx->notifDuration;
+
+ if ( !(time_s = strdup(edg_wll_TimeToDB(*valid))) )
+ {
+ edg_wll_SetError(ctx, errno, NULL);
+ goto cleanup;
+ }
+ time_s[strlen(time_s)-1] = 0;
+
+ /* Format the address
+ */
+ if ( address_override )
+ {
+ char *aux;
+
+ if ( !(aux = strchr(address_override, ':')) )
+ {
+ edg_wll_SetError(ctx, EINVAL, "Addres overrirde not in format host:port");
+ goto cleanup;
+ }
+ if ( !strncmp(address_override, "0.0.0.0", aux-address_override) )
+ trio_asprintf(&addr_s, "%s:%s", ctx->connPool[ctx->connToUse].peerName, aux+1);
+ }
+
+ /* Format DB insert statement
+ */
+ trio_asprintf(&q,
+ "insert into notif_registrations(notifid,destination,valid,userid,conditions) "
+ "values ('%|Ss','%|Ss','%|Ss','%|Ss', '<and>%|Ss</and>')",
+ nid_s, addr_s? addr_s: address_override, time_s+1, owner, xml_conds);
+
+ if ( edg_wll_ExecStmt(ctx, q, NULL) < 0 )
+ goto cleanup;
+
+ for ( i = 0; jobs[i]; i++ )
+ {
+ free(q);
+ trio_asprintf(&q,
+ "insert into notif_jobs(notifid,jobid) values ('%|Ss','%|Ss')",
+ nid_s, jobs[i]);
+ if ( edg_wll_ExecStmt(ctx, q, NULL) < 0 )
+ {
+ /* XXX: Remove uncoplete registration?
+ * Which error has to be returned?
+ */
+ free(q);
+ trio_asprintf(&q, "delete from notif_jobs where notifid='%|Ss'", nid_s);
+ edg_wll_ExecStmt(ctx, q, NULL);
+ free(q);
+ trio_asprintf(&q, "delete from notif_registrations where notifid='%|Ss'", nid_s);
+ edg_wll_ExecStmt(ctx, q, NULL);
+ goto cleanup;
+ }
+ }
+
+
+cleanup:
+ if ( q ) free(q);
+ if ( nid_s ) free(nid_s);
+ if ( time_s ) free(time_s);
+ if ( addr_s ) free(addr_s);
+ if ( xml_conds ) free(xml_conds);
+ if ( owner ) free(owner);
+ if ( jobs )
+ {
+ for ( i = 0; jobs[i]; i++ )
+ free(jobs[i]);
+ free(jobs);
+ }
+ if ( nconds ) free(nconds);
+
+ return edg_wll_Error(ctx, NULL, NULL);
+}
+
+
+int edg_wll_NotifBindServer(
+ edg_wll_Context ctx,
+ const edg_wll_NotifId nid,
+ const char *address_override,
+ time_t *valid)
+{
+ char *time_s = NULL;
+
+
+ if ( !address_override )
+ {
+ edg_wll_SetError(ctx, EINVAL, "Address parameter not given");
+ goto cleanup;
+ }
+
+ /* Format time of validity
+ */
+ *valid = time(NULL);
+ if ( ctx->peerProxyValidity
+ && (ctx->peerProxyValidity - *valid) < ctx->notifDuration )
+ *valid = ctx->peerProxyValidity;
+ else
+ *valid += ctx->notifDuration;
+
+ if ( !(time_s = strdup(edg_wll_TimeToDB(*valid))) )
+ {
+ edg_wll_SetError(ctx, errno, "Formating validity time");
+ goto cleanup;
+ }
+ time_s[strlen(time_s)-1] = 0;
+
+ update_notif(ctx, nid, NULL, address_override, (const char *)(time_s+1));
+
+cleanup:
+ if ( time_s ) free(time_s);
+
+ return edg_wll_Error(ctx, NULL, NULL);
+}
+
+int edg_wll_NotifChangeServer(
+ edg_wll_Context ctx,
+ const edg_wll_NotifId id,
+ edg_wll_QueryRec const * const *conditions,
+ edg_wll_NotifChangeOp op)
+{
+ return edg_wll_SetError(ctx, EINVAL, "Not yet implemented");
+}
+
+int edg_wll_NotifRefreshServer(
+ edg_wll_Context ctx,
+ const edg_wll_NotifId nid,
+ time_t *valid)
+{
+ char *time_s = NULL;
+
+
+ /* Format time of validity
+ */
+ *valid = time(NULL);
+ if ( ctx->peerProxyValidity
+ && (ctx->peerProxyValidity - *valid) < ctx->notifDuration )
+ *valid = ctx->peerProxyValidity;
+ else
+ *valid += ctx->notifDuration;
+
+ if ( !(time_s = strdup(edg_wll_TimeToDB(*valid))) )
+ {
+ edg_wll_SetError(ctx, errno, "Formating validity time");
+ goto cleanup;
+ }
+ time_s[strlen(time_s)-1] = 0;
+
+ update_notif(ctx, nid, NULL, NULL, time_s+1);
+
+cleanup:
+ if ( time_s ) free(time_s);
+
+ return edg_wll_Error(ctx, NULL, NULL);
+}
+
+int edg_wll_NotifDropServer(
+ edg_wll_Context ctx,
+ edg_wll_NotifId *nid)
+{
+ char *owner = NULL,
+ *nid_s = NULL,
+ *stmt;
+ int ret;
+
+
+ if ( !(owner = get_user(ctx, 0)) )
+ {
+ if ( !edg_wll_Error(ctx, NULL, NULL) )
+ edg_wll_SetError(ctx, EPERM, "Unknown user");
+
+ return edg_wll_Error(ctx, NULL, NULL);
+ }
+
+ if ( !(nid_s = edg_wll_NotifIdGetUnique(nid)) )
+ goto cleanup;
+
+ /* Only the owner could remove the notification registration
+ */
+ trio_asprintf(&stmt,
+ "delete from notif_registrations where notifid='%|Ss' and userid='%|Ss'",
+ nid_s, owner);
+ if ( (ret = edg_wll_ExecStmt(ctx, stmt, NULL)) < 0 )
+ goto cleanup;
+ free(stmt);
+ if ( ret == 0 )
+ {
+ trio_asprintf(&stmt,
+ "select notifid from notif_registrations where notifid='%|Ss'", nid_s);
+ ret = edg_wll_ExecStmt(ctx, stmt, NULL);
+ if ( ret == 0 )
+ edg_wll_SetError(ctx, ENOENT, "Unknown notification ID");
+ else if ( ret > 0 )
+ edg_wll_SetError(ctx, EPERM, NULL);
+
+ goto cleanup;
+ }
+ trio_asprintf(&stmt, "delete from notif_jobs where notifid='%|Ss'", nid_s);
+ edg_wll_ExecStmt(ctx, stmt, NULL);
+
+cleanup:
+ if ( owner ) free(owner);
+ if ( nid_s ) free(nid_s);
+ if ( stmt ) free(stmt);
+
+ return edg_wll_Error(ctx, NULL, NULL);
+}
+
+static char *get_user(edg_wll_Context ctx, int create)
+{
+ edg_wll_Stmt stmt = NULL;
+ char *userid = NULL,
+ *q = NULL;
+ int ret;
+
+
+ if ( !ctx->peerName )
+ {
+ edg_wll_SetError(ctx, EPERM, "Annonymous notifications not allowed");
+ goto cleanup;
+ }
+ trio_asprintf(&q, "select userid from users where cert_subj='%|Ss'", ctx->peerName);
+ if ( edg_wll_ExecStmt(ctx, q, &stmt) < 0 )
+ goto cleanup;
+
+ /* returned value:
+ * 0 no user find - continue only when 'create' parameter is set
+ * >0 user found - return selected value
+ * <0 SQL error
+ */
+ if ( ((ret = edg_wll_FetchRow(stmt, &userid)) != 0) || !create )
+ goto cleanup;
+
+ if ( !(userid = strdup(strmd5(ctx->peerName, NULL))) )
+ {
+ edg_wll_SetError(ctx, errno, "Creating user ID");
+ goto cleanup;
+ }
+ free(q);
+ trio_asprintf(&q, "insert into users(userid,cert_subj) values ('%|Ss','%|Ss')",
+ userid, ctx->peerName);
+ if ( edg_wll_ExecStmt(ctx, q, NULL) < 0 )
+ {
+ if ( edg_wll_Error(ctx,NULL,NULL) != EEXIST )
+ {
+ free(userid);
+ userid = NULL;
+ }
+ else
+ edg_wll_ResetError(ctx);
+ }
+
+cleanup:
+ if ( q ) free(q);
+ if ( stmt ) edg_wll_FreeStmt(&stmt);
+
+ return userid;
+}
+
+static int update_notif(
+ edg_wll_Context ctx,
+ const edg_wll_NotifId nid,
+ const char *conds,
+ const char *dest,
+ const char *valid)
+{
+ char *owner = NULL,
+ *nid_s = NULL,
+ *stmt, *aux;
+ int ret;
+
+
+ if ( !(owner = get_user(ctx, 0)) )
+ {
+ if ( !edg_wll_Error(ctx, NULL, NULL) )
+ edg_wll_SetError(ctx, EPERM, "Unknown user");
+
+ return edg_wll_Error(ctx, NULL, NULL);
+ }
+
+ if ( !(nid_s = edg_wll_NotifIdGetUnique(nid)) )
+ goto cleanup;
+
+ /* Format SQL update string
+ * (Only the owner could update the notification registration)
+ */
+ stmt = strdup("update notif_registrations set");
+ if ( dest )
+ {
+ trio_asprintf(&aux, "%s destination='%|Ss'", stmt, dest);
+ free(stmt);
+ stmt = aux;
+ }
+ if ( valid )
+ {
+ trio_asprintf(&aux, "%s %svalid='%|Ss'", stmt, dest? ",": "", valid);
+ free(stmt);
+ stmt = aux;
+ }
+ if ( conds )
+ {
+ trio_asprintf(&aux, "%s %sconditions='%|Ss'",
+ stmt, (dest||valid)? ",": "", conds);
+ free(stmt);
+ stmt = aux;
+ }
+ trio_asprintf(&aux, "%s where notifid='%|Ss' and userid='%|Ss'",
+ stmt, nid_s, owner);
+ free(stmt);
+ stmt = aux;
+
+ if ( (ret = edg_wll_ExecStmt(ctx, stmt, NULL)) < 0 )
+ goto cleanup;
+ if ( ret == 0 )
+ {
+ free(stmt);
+ trio_asprintf(&stmt,
+ "select notifid from notif_registrations where notifid='%|Ss'", nid_s);
+ ret = edg_wll_ExecStmt(ctx, stmt, NULL);
+ if ( ret == 0 )
+ edg_wll_SetError(ctx, ENOENT, "Unknown notification ID");
+ else if ( ret > 0 )
+ edg_wll_SetError(ctx, EPERM, "Updating notification records");
+ }
+
+cleanup:
+ if ( owner ) free(owner);
+ if ( nid_s ) free(nid_s);
+ if ( stmt ) free(stmt);
+
+ return edg_wll_Error(ctx, NULL, NULL);
+}
--- /dev/null
+#ident "$Header$"
+
+#include <stdlib.h>
+
+#include "glite/lb/consumer.h"
+#include "glite/lb/context.h"
+
+#include "lbs_db.h"
+
+edg_wll_ErrorCode edg_wll_Open(edg_wll_Context ctx, char *cs)
+{
+ return edg_wll_DBConnect(ctx,cs) ? edg_wll_Error(ctx,NULL,NULL) : 0;
+}
+
+edg_wll_ErrorCode edg_wll_Close(edg_wll_Context ctx)
+{
+ return edg_wll_ResetError(ctx);
+}
--- /dev/null
+#ifndef __EDG_WORKLOAD_LOGGING_COMMON_PURGE_H__
+#define __EDG_WORKLOAD_LOGGING_COMMON_PURGE_H__
+
+/** Server side implementation
+ * besides output to the SSL stream (in the context) it may produce
+ * the server-side dump files
+ */
+int edg_wll_PurgeServer(
+ edg_wll_Context ctx,
+ const edg_wll_PurgeRequest *request
+);
+
+#define FILE_TYPE_ANY ""
+#define FILE_TYPE_PURGE "purge"
+#define FILE_TYPE_DUMP "dump"
+#define FILE_TYPE_LOAD "load"
+
+extern int edg_wll_CreateTmpFileStorage(
+ edg_wll_Context ctx,
+ char *prefix,
+ char **fname
+);
+
+extern int edg_wll_CreateFileStorageFromTmp(
+ edg_wll_Context ctx,
+ char *tmp_type,
+ char *file_type,
+ char **fname
+);
+
+extern int edg_wll_CreateFileStorage(
+ edg_wll_Context ctx,
+ char *file_type,
+ char *prefix,
+ char **fname
+);
+
+#define edg_wll_CreateTmpDumpFile(ctx, f) edg_wll_CreateTmpFileStorage(ctx,ctx->dumpStorage,f)
+#define edg_wll_CreateTmpPurgeFile(ctx, f) edg_wll_CreateTmpFileStorage(ctx,ctx->purgeStorage,f)
+
+#define edg_wll_CreateDumpFileFromTmp(ctx, f, f2) \
+ edg_wll_CreateFileStorageFromTmp(ctx, f, FILE_TYPE_DUMP, f2)
+#define edg_wll_CreatePurgeFileFromTmp(ctx, f, f2) \
+ edg_wll_CreateFileStorageFromTmp(ctx, f, FILE_TYPE_PURGE, f2)
+
+#define edg_wll_CreateDumpFile(ctx, f) edg_wll_CreateFileStorage(ctx,FILE_TYPE_DUMP,NULL,f)
+#define edg_wll_CreatePurgeFile(ctx, f) edg_wll_CreateFileStorage(ctx,FILE_TYPE_PURGE,NULL,f)
+
+#endif
--- /dev/null
+#ident "$Header$"
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <time.h>
+#include <assert.h>
+
+#include "glite/wms/jobid/strmd5.h"
+
+#include "glite/lb/consumer.h"
+#include "glite/lb/producer.h"
+#include "glite/lb/context-int.h"
+#include "glite/lb/trio.h"
+
+
+#include "get_events.h"
+#include "index.h"
+#include "query.h"
+#include "store.h"
+#include "lb_authz.h"
+
+#define FL_SEL_STATUS 1
+#define FL_SEL_TAGS (1<<1)
+#define FL_SEL_JOB (1<<2)
+
+
+static int check_event_query_index(edg_wll_Context,const edg_wll_QueryRec **,const edg_wll_QueryRec **);
+static int check_job_query_index(edg_wll_Context, const edg_wll_QueryRec **);
+static char *jc_to_head_where(edg_wll_Context, const edg_wll_QueryRec **, int *);
+static char *ec_to_head_where(edg_wll_Context, const edg_wll_QueryRec **);
+static int match_flesh_conditions(const edg_wll_Event *,const edg_wll_QueryRec **);
+static int check_strict_jobid_cond(edg_wll_Context, const edg_wll_QueryRec **);
+
+static int cmp_string(const char *,edg_wll_QueryOp,const char *);
+static int is_all_query(const edg_wll_QueryRec **);
+
+
+
+#define sizofa(a) (sizeof(a)/sizeof((a)[0]))
+
+int edg_wll_QueryEventsServer(
+ edg_wll_Context ctx,
+ int noAuth,
+ const edg_wll_QueryRec **job_conditions,
+ const edg_wll_QueryRec **event_conditions,
+ edg_wll_Event **events)
+{
+ char *job_where = NULL,
+ *event_where = NULL,
+ *qbase = NULL,
+ *q = NULL,
+ *res[11];
+ edg_wll_Event *out = NULL;
+ edg_wll_Stmt sh = NULL;
+ int i = 0,
+ ret = 0,
+ offset = 0, limit = 0,
+ limit_loop = 1,
+ eperm = 0;
+
+
+ edg_wll_ResetError(ctx);
+
+ if ( (ctx->p_query_results == EDG_WLL_QUERYRES_ALL) &&
+ (!job_conditions || !job_conditions[0] || job_conditions[1] ||
+ (job_conditions[0][0].attr != EDG_WLL_QUERY_ATTR_JOBID) ||
+ (job_conditions[0][1].attr != EDG_WLL_QUERY_ATTR_UNDEF)) )
+ {
+ edg_wll_SetError(ctx, EINVAL, "Invalid parameter EDG_WLL_PARAM_QUERY_RESULTS");
+ goto cleanup;
+ }
+
+ if ((!ctx->noIndex && check_event_query_index(ctx,job_conditions,event_conditions)) ||
+ check_strict_jobid_cond(ctx,job_conditions) ||
+ check_strict_jobid_cond(ctx,event_conditions))
+ goto cleanup;
+
+ if (event_conditions && *event_conditions && (*event_conditions)->attr &&
+ !(event_where = ec_to_head_where(ctx,event_conditions)))
+ goto cleanup;
+
+ if ( job_conditions && *job_conditions && (*job_conditions)->attr &&
+ !(job_where = jc_to_head_where(ctx, job_conditions, &i)) )
+ goto cleanup;
+
+/* XXX: similar query in srv_purge.c ! They has to match due to common
+ * convert_event_head() called on the result
+ */
+ trio_asprintf(&qbase,"SELECT e.event,j.userid,j.dg_jobid,e.code,"
+ "e.prog,e.host,u.cert_subj,e.time_stamp,e.usec,e.level,e.arrived "
+ "FROM events e,users u,jobs j%s "
+ "WHERE %se.jobid=j.jobid AND e.userid=u.userid AND e.code != %d "
+ "%s %s %s %s",
+ i & FL_SEL_STATUS ? ",states s" : "",
+ i & FL_SEL_STATUS ? "s.jobid=j.jobid AND " : "",
+ EDG_WLL_EVENT_UNDEF,
+ job_where ? "AND" : "",
+ job_where ? job_where : "",
+ event_where ? "AND" : "",
+ event_where ? event_where : "");
+
+ if ( ctx->softLimit )
+ {
+ if ( ctx->hardEventsLimit )
+ limit = ctx->softLimit < ctx->hardEventsLimit? ctx->softLimit: ctx->hardEventsLimit;
+ else
+ limit = ctx->softLimit;
+ }
+ else if ( ctx->hardEventsLimit )
+ limit = ctx->hardEventsLimit;
+ else
+ limit = 0;
+
+ i = 0;
+ out = calloc(1, sizeof(*out));
+ do
+ {
+ if ( limit )
+ trio_asprintf(&q, "%s LIMIT %d, %d", qbase, offset, limit);
+ else if ( !q )
+ q = qbase;
+
+// printf("\nquery: %s\n\n", q);
+ ret = edg_wll_ExecStmt(ctx, q, &sh);
+ if ( limit )
+ free(q);
+ if ( ret < 0 )
+ {
+ edg_wll_FreeStmt(&sh);
+ goto cleanup;
+ }
+ if ( ret == 0 )
+ {
+ limit_loop = 0;
+ goto limit_cycle_cleanup;
+ }
+ if ( !limit || (ret < limit) )
+ limit_loop = 0;
+
+ offset += ret;
+ while ( (ret = edg_wll_FetchRow(sh, res)) == sizofa(res) )
+ {
+ int n = atoi(res[0]);
+ free(res[0]);
+
+ if ( convert_event_head(ctx, res+2, out+i) || edg_wll_get_event_flesh(ctx, n, out+i) )
+ {
+ free(res[1]);
+ memset(out+i, 0, sizeof(*out));
+ edg_wll_FreeStmt(&sh);
+ goto cleanup;
+ }
+
+ if ( !match_flesh_conditions(out+i,event_conditions) || check_strict_jobid(ctx,out[i].any.jobId) )
+ {
+ edg_wll_FreeEvent(out+i);
+ edg_wll_ResetError(ctx); /* check_strict_jobid() sets it */
+ goto fetch_cycle_cleanup;
+ }
+
+ if ( !noAuth )
+ {
+ if (!ctx->peerName || strcmp(res[1],strmd5(ctx->peerName,NULL))) {
+ edg_wll_Acl acl = NULL;
+ char *jobid = NULL;
+
+ ret = edg_wll_GetACL(ctx, out[i].any.jobId, &acl);
+ free(jobid);
+ if (ret || acl == NULL) {
+ eperm = 1;
+ edg_wll_FreeEvent(out+i);
+ edg_wll_ResetError(ctx); /* XXX: should be reported somewhere at least in debug mode */
+ goto fetch_cycle_cleanup;
+ }
+
+ ret = edg_wll_CheckACL(ctx, acl, EDG_WLL_PERM_READ);
+ edg_wll_FreeAcl(acl);
+ if (ret) {
+ eperm = 1;
+ edg_wll_FreeEvent(out+i);
+ edg_wll_ResetError(ctx); /* XXX: should be reported somewhere at least in debug mode */
+ goto fetch_cycle_cleanup;
+ }
+ }
+ }
+
+ if ( (ctx->p_query_results != EDG_WLL_QUERYRES_ALL) && limit && (i+1 > limit) )
+ {
+ free(res[1]);
+ memset(out+i, 0, sizeof(*out));
+ edg_wll_SetError(ctx, E2BIG, "Query result size limit exceeded");
+ if ( ctx->p_query_results == EDG_WLL_QUERYRES_LIMITED )
+ {
+ limit_loop = 0;
+ goto limit_cycle_cleanup;
+ }
+ goto cleanup;
+ }
+
+ i++;
+ out = (edg_wll_Event *) realloc(out, (i+1) * sizeof(*out));
+
+fetch_cycle_cleanup:
+ memset(out+i, 0, sizeof(*out));
+ free(res[1]);
+ }
+limit_cycle_cleanup:
+ edg_wll_FreeStmt(&sh);
+ } while ( limit_loop );
+
+ if ( i == 0 && eperm )
+ edg_wll_SetError(ctx, EPERM, "matching events found but authorization failed");
+ else if ( i == 0 )
+ edg_wll_SetError(ctx, ENOENT, "no matching events found");
+ else
+ {
+ edg_wll_SortEvents(out);
+ *events = out;
+ out = NULL;
+ }
+
+cleanup:
+ if ( out )
+ {
+ for ( i = 0; out[i].type; i++ )
+ edg_wll_FreeEvent(out+i);
+ free(out);
+ }
+ free(qbase);
+ free(job_where);
+ free(event_where);
+
+ return edg_wll_Error(ctx,NULL,NULL);
+}
+
+int edg_wll_QueryJobsServer(
+ edg_wll_Context ctx,
+ const edg_wll_QueryRec **conditions,
+ int flags,
+ edg_wlc_JobId **jobs,
+ edg_wll_JobStat **states)
+{
+ char *job_where = NULL,
+ *state_where = NULL,
+ *tags_where = NULL,
+ *q = NULL,
+ *qbase = NULL,
+ *res[3];
+ edg_wlc_JobId *jobs_out = NULL;
+ edg_wll_JobStat *states_out = NULL;
+ edg_wll_Stmt sh;
+ int i = 0,
+ ret = 0,
+ eperm = 0,
+ limit = 0, offset = 0,
+ limit_loop = 1;
+
+
+ memset(res,0,sizeof res);
+ edg_wll_ResetError(ctx);
+
+ if ( !conditions )
+ {
+ edg_wll_SetError(ctx, EINVAL, "empty condition list");
+ goto cleanup;
+ }
+
+ if ( (ctx->p_query_results == EDG_WLL_QUERYRES_ALL) &&
+ (!conditions[0] || conditions[1] ||
+ (conditions[0][0].attr != EDG_WLL_QUERY_ATTR_OWNER) ||
+ (conditions[0][1].attr != EDG_WLL_QUERY_ATTR_UNDEF)) )
+ {
+ edg_wll_SetError(ctx, EINVAL, "Invalid parameter EDG_WLL_PARAM_QUERY_RESULTS");
+ goto cleanup;
+ }
+
+ if ( (!ctx->noIndex && check_job_query_index(ctx, conditions)) || check_strict_jobid_cond(ctx,conditions))
+ goto cleanup;
+
+ if ( !(job_where = jc_to_head_where(ctx, conditions, &i)) )
+ goto cleanup;
+
+ if ( (i & FL_SEL_STATUS) )
+ trio_asprintf(&qbase,"SELECT DISTINCT j.dg_jobid,j.userid "
+ "FROM jobs j, states s WHERE j.jobid=s.jobid AND %s", job_where);
+ else
+ trio_asprintf(&qbase,"SELECT DISTINCT j.dg_jobid,j.userid "
+ "FROM jobs j WHERE %s", job_where);
+
+ if ( ctx->softLimit )
+ {
+ if ( ctx->hardJobsLimit )
+ limit = ctx->softLimit < ctx->hardJobsLimit? ctx->softLimit: ctx->hardJobsLimit;
+ else
+ limit = ctx->softLimit;
+ }
+ else if ( ctx->hardJobsLimit )
+ limit = ctx->hardJobsLimit;
+ else
+ limit = 0;
+
+ jobs_out = calloc(1, sizeof(*jobs_out));
+ states_out = calloc(1, sizeof(*states_out));
+ i = 0;
+ do
+ {
+ if ( limit )
+ trio_asprintf(&q, "%s LIMIT %d, %d", qbase, offset, limit);
+ else if ( !q )
+ q = qbase;
+
+// printf("\nquery: %s\n\n", q);
+ ret = edg_wll_ExecStmt(ctx, q, &sh);
+ if ( limit )
+ free(q);
+ if ( ret < 0 )
+ {
+ edg_wll_FreeStmt(&sh);
+ goto cleanup;
+ }
+ if ( ret == 0 )
+ {
+ limit_loop = 0;
+ goto limit_cycle_cleanup;
+ }
+ if ( !limit || (ret < limit) )
+ limit_loop = 0;
+
+ offset += ret;
+ while ( (ret=edg_wll_FetchRow(sh,res)) > 0 )
+ {
+ if ( (ret = edg_wlc_JobIdParse(res[0], jobs_out+i)) )
+ { /* unlikely to happen, internal inconsistency */
+ char buf[200];
+ snprintf(buf,sizeof buf,"JobIdParse(%s)",res[0]);
+ edg_wll_SetError(ctx,ret,buf);
+ free(res[0]); free(res[1]); free(res[2]);
+ jobs_out[i] = NULL;
+ goto cleanup;
+ }
+
+ if ( check_strict_jobid(ctx, jobs_out[i]) )
+ {
+ edg_wlc_JobIdFree(jobs_out[i]);
+ goto fetch_cycle_cleanup;
+ }
+
+ if ( edg_wll_JobStatus(ctx, jobs_out[i], flags, &states_out[i]) )
+ {
+ edg_wlc_JobIdFree(jobs_out[i]);
+ if (edg_wll_Error(ctx,NULL,NULL) == EPERM) eperm = 1;
+ goto fetch_cycle_cleanup;
+ }
+
+ if ( !match_status(ctx, states_out+i, conditions) )
+ {
+ edg_wlc_JobIdFree(jobs_out[i]);
+ edg_wll_FreeStatus(states_out+i);
+ edg_wll_ResetError(ctx); /* check_strict_jobid() sets it */
+ goto fetch_cycle_cleanup;
+ }
+
+#if 0
+ if ( !ctx->noAuth && (!ctx->peerName || strcmp(res[1], strmd5(ctx->peerName, NULL))) )
+ {
+ eperm = 1;
+ edg_wlc_JobIdFree(jobs_out[i]);
+ edg_wll_FreeStatus(states_out+i);
+ goto fetch_cycle_cleanup;
+ }
+#endif
+
+ if ( (ctx->p_query_results != EDG_WLL_QUERYRES_ALL) && limit && (i+1 > limit) )
+ {
+ edg_wll_SetError(ctx, E2BIG, "Query result size limit exceeded");
+ free(res[0]); free(res[1]); free(res[2]);
+ memset(states_out+i, 0, sizeof(*states_out));
+ jobs_out[i] = NULL;
+ if ( ctx->p_query_results == EDG_WLL_QUERYRES_LIMITED )
+ {
+ limit_loop = 0;
+ goto limit_cycle_cleanup;
+ }
+ goto cleanup;
+ }
+
+ i++;
+ jobs_out = (edg_wlc_JobId *) realloc(jobs_out, (i+1) * sizeof(*jobs_out));
+ states_out = (edg_wll_JobStat *) realloc(states_out, (i+1) * sizeof(*states_out));
+
+fetch_cycle_cleanup:
+ free(res[0]); free(res[1]); free(res[2]);
+ memset(states_out+i, 0, sizeof(*states_out));
+ jobs_out[i] = NULL;
+ }
+limit_cycle_cleanup:
+ edg_wll_FreeStmt(&sh);
+ } while ( limit_loop );
+
+ if ( eperm && !*jobs_out )
+ edg_wll_SetError(ctx, EPERM, "matching jobs found but authorization failed");
+
+ if ( i && (ret == 0) )
+ {
+ if ( states )
+ {
+ *states = states_out;
+ states_out = NULL;
+ }
+ if ( jobs )
+ {
+ *jobs = jobs_out;
+ jobs_out = NULL;
+ }
+ }
+
+
+cleanup:
+ free(qbase);
+ free(state_where);
+ free(tags_where);
+ free(job_where);
+
+ if (jobs_out)
+ {
+ for ( i = 0; jobs_out[i]; i++ )
+ edg_wlc_JobIdFree(jobs_out[i]);
+ free(jobs_out);
+ }
+
+ if (states_out)
+ {
+ for (i=0; states_out[i].state; i++) edg_wll_FreeStatus(states_out+i);
+ free(states_out);
+ }
+
+ return edg_wll_Error(ctx,NULL,NULL);
+}
+
+
+static int check_event_query_index(edg_wll_Context ctx,const edg_wll_QueryRec **jc,const edg_wll_QueryRec **ec)
+{
+ int i, j;
+
+ if (check_job_query_index(ctx,jc) == 0) return 0;
+ edg_wll_ResetError(ctx);
+
+ if (ec && *ec) for (i=0; ec[i]; i++) for (j=0; ec[i][j].attr; j++) switch (ec[i][j].attr) {
+ case EDG_WLL_QUERY_ATTR_TIME:
+ return 0;
+ default: break;
+ }
+ return edg_wll_SetError(ctx,EDG_WLL_ERROR_NOINDEX,
+ is_all_query(jc) ? "\"-all\" queries denied by server configuration" : NULL);
+}
+
+static int check_job_query_index(edg_wll_Context ctx, const edg_wll_QueryRec **jc)
+{
+ int i, j, jj;
+
+
+ edg_wll_ResetError(ctx);
+
+ if ( !jc || !*jc )
+ return edg_wll_SetError(ctx,EDG_WLL_ERROR_NOINDEX,"unrestricted queries unsupported");
+
+ /*
+ * First check presense of jobid - Primary key
+ */
+ for ( i = 0; jc[i]; i++ ) for ( j = 0; jc[i][j].attr; j++ )
+ if ( jc[i][j].attr == EDG_WLL_QUERY_ATTR_JOBID ) return 0;
+
+ if ( !ctx->job_index )
+ return edg_wll_SetError(ctx, EDG_WLL_ERROR_NOINDEX, "no indices configured: jobid required in query");
+
+ for ( j = 0; ctx->job_index[j]; j++ )
+ {
+ if ( !ctx->job_index[j][0].attr )
+ continue;
+
+ if ( ctx->job_index[j][1].attr )
+ {
+ /*
+ * check multi comlumn indexes
+ */
+ for ( jj = 0; ctx->job_index[j][jj].attr; jj++ )
+ {
+ for ( i = 0; jc[i]; i++ )
+ if ( !edg_wll_CmpColumn(&ctx->job_index[j][jj], &jc[i][0]) ) break;
+ if ( !jc[i] )
+ break;
+ }
+ if ( !ctx->job_index[j][jj].attr )
+ return 0;
+ }
+ else
+ for ( i = 0; jc[i]; i++ )
+ if ( !edg_wll_CmpColumn(&ctx->job_index[j][0], &jc[i][0]) ) return 0;
+ }
+
+ return edg_wll_SetError(ctx,EDG_WLL_ERROR_NOINDEX,
+ is_all_query(jc) ? "\"-all\" queries denied by server configuration" : NULL);
+}
+
+#define opToString(op) \
+ ((op) == EDG_WLL_QUERY_OP_EQUAL ? "=" : \
+ ((op) == EDG_WLL_QUERY_OP_UNEQUAL ? "!=" : \
+ ((op) == EDG_WLL_QUERY_OP_LESS ? "<" : ">" )))
+
+static char *ec_to_head_where(edg_wll_Context ctx,const edg_wll_QueryRec **ec)
+{
+ int n, ct, m;
+ char msg[100],
+ *out,
+ *aux,
+ *conds, *retconds,
+ *dbt;
+
+
+ /*
+ * check correctness only
+ */
+ for ( ct = m = 0; ec[m]; m++ )
+ {
+ for ( n = 0; ec[m][n].attr; n++ ) switch ( ec[m][n].attr )
+ {
+ case EDG_WLL_QUERY_ATTR_HOST:
+ if ( ec[m][n].op != EDG_WLL_QUERY_OP_EQUAL && ec[m][n].op != EDG_WLL_QUERY_OP_UNEQUAL )
+ {
+ edg_wll_SetError(ctx, EINVAL, "only `=' and '!=' supported with host attr");
+ return NULL;
+ }
+ ct++;
+ break;
+
+ case EDG_WLL_QUERY_ATTR_SOURCE:
+ if ( ec[m][n].op != EDG_WLL_QUERY_OP_EQUAL && ec[m][n].op != EDG_WLL_QUERY_OP_UNEQUAL )
+ {
+ edg_wll_SetError(ctx, EINVAL, "only `=' and '!=' supported with host attr");
+ return NULL;
+ }
+ ct++;
+ break;
+
+ case EDG_WLL_QUERY_ATTR_USERTAG:
+ if ( ec[m][n].op != EDG_WLL_QUERY_OP_EQUAL && ec[m][n].op != EDG_WLL_QUERY_OP_UNEQUAL )
+ {
+ edg_wll_SetError(ctx, EINVAL, "only `=' and '!=' supported with usertag attr");
+ return NULL;
+ }
+ ct++;
+ break;
+
+ case EDG_WLL_QUERY_ATTR_INSTANCE:
+ if ( ec[m][n].op != EDG_WLL_QUERY_OP_EQUAL && ec[m][n].op != EDG_WLL_QUERY_OP_UNEQUAL )
+ {
+ edg_wll_SetError(ctx, EINVAL, "only `=' and '!=' supported with instance attr");
+ return NULL;
+ }
+ ct++;
+ break;
+
+ case EDG_WLL_QUERY_ATTR_EVENT_TYPE:
+ case EDG_WLL_QUERY_ATTR_LEVEL:
+ /*
+ * Any op allowed - but be careful
+ */
+ case EDG_WLL_QUERY_ATTR_TIME:
+ /* any operator allowed */
+ ct++;
+ break;
+
+ default:
+ sprintf(msg, "ec_to_head_where(): attr=%d unsupported", ec[m][n].attr);
+ edg_wll_SetError(ctx, EINVAL, msg);
+ return NULL;
+ }
+ }
+
+ if ( ct == 0 )
+ {
+ edg_wll_SetError(ctx,EINVAL,"ec_to_head_where(): empty conditions");
+ return NULL;
+ }
+
+ conds = retconds = NULL;
+ for ( m = 0; ec[m]; m++ )
+ {
+ /*
+ * conditions captured by match_flesh_conditions() have to be skipped here.
+ * with all conditions in same "or clause"
+ */
+ for ( n = 0; ec[m][n].attr; n++ )
+ if ( (ec[m][n].attr == EDG_WLL_QUERY_ATTR_USERTAG)
+ || (ec[m][n].attr == EDG_WLL_QUERY_ATTR_INSTANCE) )
+ break;
+ if ( ec[m][n].attr )
+ continue;
+
+ for ( n = 0; ec[m][n].attr; n++ ) switch ( ec[m][n].attr )
+ {
+ case EDG_WLL_QUERY_ATTR_TIME:
+ dbt = edg_wll_TimeToDB(ec[m][n].value.t.tv_sec);
+ if ( conds )
+ {
+ if ( ec[m][n].op == EDG_WLL_QUERY_OP_WITHIN )
+ {
+ trio_asprintf(&aux, "%s", dbt);
+ dbt = edg_wll_TimeToDB(ec[m][n].value2.t.tv_sec);
+ trio_asprintf(&out, "%s OR (e.time_stamp >= %s AND e.time_stamp <= %s)", conds, aux, dbt);
+ free(aux);
+ }
+ else
+ trio_asprintf(&out, "%s OR e.time_stamp %s %s", conds, opToString(ec[m][n].op), dbt);
+ free(conds);
+ conds = out;
+ }
+ else if ( ec[m][n].op == EDG_WLL_QUERY_OP_WITHIN )
+ {
+ trio_asprintf(&aux, "%s", dbt);
+ dbt = edg_wll_TimeToDB(ec[m][n].value2.t.tv_sec);
+ trio_asprintf(&conds, "(e.time_stamp >= %s AND e.time_stamp <= %s)", aux, dbt);
+ free(aux);
+ }
+ else
+ trio_asprintf(&conds, "e.time_stamp %s %s", opToString(ec[m][n].op), dbt);
+ break;
+
+ case EDG_WLL_QUERY_ATTR_LEVEL:
+ if ( conds )
+ {
+ if ( ec[m][n].op == EDG_WLL_QUERY_OP_WITHIN )
+ trio_asprintf(&out, "%s OR (e.level >= %d AND e.level <= %d)", conds, ec[m][n].value.i, ec[m][n].value2.i);
+ else
+ trio_asprintf(&out, "%s OR e.level %s %d", conds, opToString(ec[m][n].op), ec[m][n].value.i);
+ free(conds); conds = out;
+ }
+ else
+ if ( ec[m][n].op == EDG_WLL_QUERY_OP_WITHIN )
+ trio_asprintf(&conds, "(e.level >= %d AND e.level <= %d)", ec[m][n].value.i, ec[m][n].value2.i);
+ else
+ trio_asprintf(&conds, "e.level %s %d", opToString(ec[m][n].op), ec[m][n].value.i);
+ break;
+
+ case EDG_WLL_QUERY_ATTR_SOURCE:
+ aux = edg_wll_SourceToString(ec[m][n].value.i);
+ if ( conds )
+ {
+ trio_asprintf(&out, "%s OR e.prog %s '%|Ss'", conds, opToString(ec[m][n].op), aux);
+ free(conds); conds = out;
+ }
+ else
+ trio_asprintf(&conds, "e.prog %s '%|Ss'", opToString(ec[m][n].op), aux);
+ free(aux);
+ break;
+
+ case EDG_WLL_QUERY_ATTR_HOST:
+ if ( conds )
+ {
+ trio_asprintf(&out, "%s OR e.host %s '%|Ss'", conds, opToString(ec[m][n].op), ec[m][n].value.c);
+ free(conds); conds = out;
+ }
+ else
+ trio_asprintf(&conds, "e.host %s '%|Ss'", opToString(ec[m][n].op), ec[m][n].value.c);
+ break;
+
+ case EDG_WLL_QUERY_ATTR_EVENT_TYPE:
+ if ( conds )
+ {
+ if ( ec[m][n].op == EDG_WLL_QUERY_OP_WITHIN )
+ trio_asprintf(&out, "%s OR (e.code >= %d AND e.code <= %d)", conds, ec[m][n].value.i, ec[m][n].value2.i);
+ else
+ trio_asprintf(&out, "%s OR e.code %s %d", conds, opToString(ec[m][n].op), ec[m][n].value.i);
+ free(conds); conds = out;
+ }
+ else
+ if ( ec[m][n].op == EDG_WLL_QUERY_OP_WITHIN )
+ trio_asprintf(&conds, "(e.code >= %d AND e.code <= %d)", ec[m][n].value.i, ec[m][n].value2.i);
+ else
+ trio_asprintf(&conds, "e.code %s %d", opToString(ec[m][n].op), ec[m][n].value.i);
+ break;
+
+ default:
+ return NULL;
+ }
+
+ if ( !conds )
+ continue;
+
+ if ( retconds )
+ {
+ trio_asprintf(&out, "%s AND (%s)", retconds, conds);
+ free(retconds); retconds = out;
+ free(conds); conds = NULL;
+ }
+ else
+ {
+ trio_asprintf(&retconds, "(%s)", conds);
+ free(conds); conds = NULL;
+ }
+ }
+
+ return retconds;
+}
+
+static int is_indexed(const edg_wll_QueryRec *cond, const edg_wll_Context ctx)
+{
+ int i, j;
+
+ if ( !(ctx->job_index) )
+ return 0;
+
+ for ( i = 0; ctx->job_index[i]; i++ ) for ( j = 0; ctx->job_index[i][j].attr; j++ )
+ if ( !edg_wll_CmpColumn(&ctx->job_index[i][j], cond) ) return 1;
+
+ return 0;
+}
+
+/*
+ * use where_flags to recognize which table to jois in SQL select
+ *
+ */
+static char *jc_to_head_where(
+ edg_wll_Context ctx,
+ const edg_wll_QueryRec **jc,
+ int *where_flags)
+{
+ int ct, n, m;
+ char *aux,
+ *tmps,
+ *dbt,
+ *cname = NULL,
+ msg[100];
+ char *conds, *retconds;
+
+
+ retconds = conds = NULL;
+
+ /*
+ * check correctness only
+ */
+ for ( ct = m = 0; jc[m]; m++ ) for ( n = 0; jc[m][n].attr; n++ )
+ {
+ if ( (jc[m][0].attr != jc[m][n].attr)
+ || ( (jc[m][n].attr == EDG_WLL_QUERY_ATTR_USERTAG)
+ && strcmp(jc[m][0].attr_id.tag, jc[m][n].attr_id.tag)) )
+ {
+ edg_wll_SetError(ctx, EINVAL, "only same attribute types supported in 'or' expressions");
+ return NULL;
+ }
+
+ switch ( jc[m][n].attr )
+ {
+ case EDG_WLL_QUERY_ATTR_JOBID:
+ ct++;
+ if ( jc[m][n].op != EDG_WLL_QUERY_OP_EQUAL && jc[m][n].op != EDG_WLL_QUERY_OP_UNEQUAL )
+ {
+ edg_wll_SetError(ctx, EINVAL, "only `=' and '!=' supported with jobid");
+ return NULL;
+ }
+ break;
+
+ case EDG_WLL_QUERY_ATTR_OWNER:
+ ct++;
+ if ( jc[m][n].op != EDG_WLL_QUERY_OP_EQUAL && jc[m][n].op != EDG_WLL_QUERY_OP_UNEQUAL )
+ {
+ edg_wll_SetError(ctx, EINVAL, "only `=' and '!=' supported with job owner");
+ return NULL;
+ }
+ break;
+
+ case EDG_WLL_QUERY_ATTR_LOCATION:
+ ct++;
+ if ( jc[m][n].op != EDG_WLL_QUERY_OP_EQUAL && jc[m][n].op != EDG_WLL_QUERY_OP_UNEQUAL )
+ {
+ edg_wll_SetError(ctx, EINVAL, "only `=' and '!=' supported with job location");
+ return NULL;
+ }
+ break;
+
+ case EDG_WLL_QUERY_ATTR_DESTINATION:
+ ct++;
+ if ( jc[m][n].op != EDG_WLL_QUERY_OP_EQUAL && jc[m][n].op != EDG_WLL_QUERY_OP_UNEQUAL )
+ {
+ edg_wll_SetError(ctx, EINVAL, "only `=' and '!=' supported with job destinations");
+ return NULL;
+ }
+ break;
+
+ case EDG_WLL_QUERY_ATTR_PARENT:
+ ct++;
+ if ( jc[m][n].op != EDG_WLL_QUERY_OP_EQUAL && jc[m][n].op != EDG_WLL_QUERY_OP_UNEQUAL )
+ {
+ edg_wll_SetError(ctx, EINVAL, "only `=' and '!=' supported with job parent");
+ return NULL;
+ }
+ break;
+
+ case EDG_WLL_QUERY_ATTR_RESUBMITTED:
+ ct++;
+ if ( jc[m][n].op != EDG_WLL_QUERY_OP_EQUAL && jc[m][n].op != EDG_WLL_QUERY_OP_UNEQUAL )
+ {
+ edg_wll_SetError(ctx, EINVAL, "only `=' and '!=' supported with resubmitted attr");
+ return NULL;
+ }
+ break;
+
+ case EDG_WLL_QUERY_ATTR_TIME:
+ if ( jc[m][n].attr_id.state == EDG_WLL_JOB_UNDEF )
+ {
+ edg_wll_SetError(ctx, EINVAL, "Time attribut have to be associated with status specification");
+ return NULL;
+ }
+ ct++;
+ break;
+ case EDG_WLL_QUERY_ATTR_DONECODE:
+ case EDG_WLL_QUERY_ATTR_EXITCODE:
+ case EDG_WLL_QUERY_ATTR_STATUS:
+ ct++;
+ break;
+
+ case EDG_WLL_QUERY_ATTR_USERTAG:
+ ct++;
+ break;
+
+ default:
+ sprintf(msg, "jc_to_head_where(): attr=%d unsupported", jc[m][n].attr);
+ edg_wll_SetError(ctx, EINVAL, msg);
+ return NULL;
+ }
+ }
+
+ if ( ct == 0 )
+ {
+ edg_wll_SetError(ctx, EINVAL, "jc_to_head_where(): empty conditions");
+ return NULL;
+ }
+
+ /*
+ * Now process conversion
+ */
+ for ( m = 0; jc[m]; m++ )
+ {
+ for ( n = 0; jc[m][n].attr; n++ ) switch (jc[m][n].attr)
+ {
+ case EDG_WLL_QUERY_ATTR_TIME:
+ if ( !is_indexed(&(jc[m][n]), ctx)
+ || !(cname = edg_wll_QueryRecToColumn(&(jc[m][n]))) )
+ break;
+
+ *where_flags |= FL_SEL_STATUS;
+
+ dbt = edg_wll_TimeToDB(jc[m][n].value.t.tv_sec);
+ if ( conds )
+ {
+ if ( jc[m][n].op == EDG_WLL_QUERY_OP_WITHIN )
+ {
+ trio_asprintf(&aux, "%s", dbt);
+ dbt = edg_wll_TimeToDB(jc[m][n].value2.t.tv_sec);
+ trio_asprintf(&tmps, "%s OR (s.%s >= %s AND s.%s <= %s)", conds, cname, aux, cname, dbt);
+ free(aux);
+ }
+ else
+ trio_asprintf(&tmps, "%s OR s.%s %s s.%s", conds, cname, opToString(jc[m][n].op), dbt);
+
+ free(conds);
+ conds = tmps;
+ }
+ else if ( jc[m][n].op == EDG_WLL_QUERY_OP_WITHIN )
+ {
+ trio_asprintf(&aux, "%s", dbt);
+ dbt = edg_wll_TimeToDB(jc[m][n].value2.t.tv_sec);
+ trio_asprintf(&conds, "(%s >= s.%s AND s.%s <= %s)", cname, aux, cname, dbt);
+ free(aux);
+ }
+ else
+ trio_asprintf(&conds, "s.%s %s %s", cname, opToString(jc[m][n].op), dbt);
+
+ free(cname);
+ break;
+
+ case EDG_WLL_QUERY_ATTR_JOBID:
+ *where_flags |= FL_SEL_JOB;
+ aux = edg_wlc_JobIdGetUnique(jc[m][n].value.j);
+ if ( conds )
+ {
+ trio_asprintf(&tmps, "%s OR j.jobid%s'%|Ss'", conds, opToString(jc[m][n].op), aux);
+ free(conds); conds = tmps;
+ }
+ else
+ trio_asprintf(&conds, "j.jobid%s'%|Ss'", opToString(jc[m][n].op), aux);
+ free(aux);
+ break;
+
+ case EDG_WLL_QUERY_ATTR_PARENT:
+ if ( !is_indexed(&(jc[m][n]), ctx)
+ || !(cname = edg_wll_QueryRecToColumn(&(jc[m][n]))) )
+ break;
+
+ *where_flags |= FL_SEL_STATUS;
+ aux = edg_wlc_JobIdGetUnique(jc[m][n].value.j);
+ if ( conds )
+ {
+ trio_asprintf(&tmps, "%s OR s.%s%s'%|Ss'", conds, cname, opToString(jc[m][n].op), aux);
+ free(conds); conds = tmps;
+ }
+ else
+ trio_asprintf(&conds, "s.%s%s'%|Ss'", cname, opToString(jc[m][n].op), aux);
+ free(aux);
+ break;
+
+ case EDG_WLL_QUERY_ATTR_OWNER:
+ if ( !is_indexed(&(jc[m][n]), ctx)
+ || !(cname = edg_wll_QueryRecToColumn(&(jc[m][n]))) )
+ break;
+
+ if ( !jc[m][n].value.c && !ctx->peerName )
+ {
+ edg_wll_SetError(ctx, EPERM, "jc_to_head_where(): ctx->peerName empty");
+ free(cname); free(conds); free(retconds);
+ return NULL;
+ }
+
+ *where_flags |= FL_SEL_STATUS;
+ if ( conds )
+ {
+ if ( jc[m][n].value.c )
+ trio_asprintf(&tmps, "%s OR s.%s%s'%|Ss'", conds, cname, opToString(jc[m][n].op), jc[m][n].value.c);
+ else
+ trio_asprintf(&tmps, "%s OR s.%s%s'%|Ss'", conds, cname, opToString(jc[m][n].op), ctx->peerName);
+ free(conds); conds = tmps;
+ }
+ else
+ {
+ if ( jc[m][n].value.c )
+ trio_asprintf(&conds, "s.%s%s'%|Ss'", cname, opToString(jc[m][n].op), jc[m][n].value.c);
+ else
+ trio_asprintf(&conds, "s.%s%s'%|Ss'", cname, opToString(jc[m][n].op), ctx->peerName);
+ }
+ break;
+
+ case EDG_WLL_QUERY_ATTR_DONECODE:
+ case EDG_WLL_QUERY_ATTR_EXITCODE:
+ case EDG_WLL_QUERY_ATTR_STATUS:
+ if ( !is_indexed(&(jc[m][n]), ctx)
+ || !(cname = edg_wll_QueryRecToColumn(&(jc[m][n]))) )
+ break;
+
+ *where_flags |= FL_SEL_STATUS;
+ if ( conds )
+ {
+ if ( jc[m][n].op == EDG_WLL_QUERY_OP_WITHIN )
+ trio_asprintf(&tmps, "%s OR (s.%s >= %d AND s.%s <= %d)", conds, cname, jc[m][n].value.i, cname, jc[m][n].value2.i);
+ else
+ trio_asprintf(&tmps, "%s OR s.%s %s %d", conds, cname, opToString(jc[m][n].op), jc[m][n].value.i);
+ free(conds); conds = tmps;
+ }
+ else
+ if ( jc[m][n].op == EDG_WLL_QUERY_OP_WITHIN )
+ trio_asprintf(&conds, "(s.%s >= %d AND s.%s <= %d)", cname, jc[m][n].value.i, cname, jc[m][n].value2.i);
+ else
+ trio_asprintf(&conds, "s.%s %s %d", cname, opToString(jc[m][n].op),jc[m][n].value.i);
+
+ free(cname);
+ break;
+
+ case EDG_WLL_QUERY_ATTR_DESTINATION:
+ case EDG_WLL_QUERY_ATTR_LOCATION:
+ case EDG_WLL_QUERY_ATTR_RESUBMITTED:
+ case EDG_WLL_QUERY_ATTR_USERTAG:
+ if ( !is_indexed(&(jc[m][n]), ctx)
+ || !(cname = edg_wll_QueryRecToColumn(&(jc[m][n]))) )
+ break;
+
+ *where_flags |= FL_SEL_STATUS;
+ if ( conds )
+ {
+ trio_asprintf(&tmps, "%s OR s.%s%s'%s'", conds, cname, opToString(jc[m][n].op), jc[m][n].value.c);
+ free(conds); conds = tmps;
+ }
+ else
+ trio_asprintf(&conds, "s.%s%s'%s'", cname, opToString(jc[m][n].op), jc[m][n].value.c);
+
+ free(cname);
+ break;
+
+ default:
+ /* this may never occure, but keep compiler happy */
+ break;
+ }
+
+ if ( !conds ) continue;
+
+ if ( retconds )
+ {
+ trio_asprintf(&tmps, "%s AND (%s)", retconds, conds);
+ free(retconds); retconds = tmps;
+ free(conds); conds = NULL;
+ }
+ else
+ {
+ trio_asprintf(&retconds, "(%s)", conds);
+ free(conds); conds = NULL;
+ }
+ }
+
+ return retconds;
+}
+
+
+static int match_flesh_conditions(const edg_wll_Event *e,const edg_wll_QueryRec **ec)
+{
+ int i, j;
+
+
+ if ( !ec )
+ return 1;
+
+ for ( i = 0; ec[i]; i++ )
+ {
+ j = 0;
+ while ( (ec[i][j].attr)
+ && (ec[i][j].attr != EDG_WLL_QUERY_ATTR_USERTAG)
+ && (ec[i][j].attr != EDG_WLL_QUERY_ATTR_INSTANCE) ) j++;
+ if ( !ec[i][j].attr )
+ continue;
+
+ for ( j = 0; ec[i][j].attr; j++ )
+ {
+ if ( ec[i][j].attr == EDG_WLL_QUERY_ATTR_TIME )
+ {
+ if ( ((ec[i][j].op == EDG_WLL_QUERY_OP_EQUAL) && (e->any.timestamp.tv_sec == ec[i][j].value.t.tv_sec))
+ || ((ec[i][j].op == EDG_WLL_QUERY_OP_LESS) && (e->any.timestamp.tv_sec < ec[i][j].value.t.tv_sec))
+ || ((ec[i][j].op == EDG_WLL_QUERY_OP_GREATER) && (e->any.timestamp.tv_sec < ec[i][j].value.t.tv_sec))
+ || ( (ec[i][j].op == EDG_WLL_QUERY_OP_WITHIN)
+ && (e->any.timestamp.tv_sec >= ec[i][j].value.t.tv_sec)
+ && (e->any.timestamp.tv_sec <= ec[i][j].value2.t.tv_sec)) )
+ break;
+ }
+ else if ( ec[i][j].attr == EDG_WLL_QUERY_ATTR_SOURCE )
+ {
+ if ( e->any.source == EDG_WLL_SOURCE_NONE )
+ continue;
+ if ( ((ec[i][j].op == EDG_WLL_QUERY_OP_EQUAL) && (e->any.source == ec[i][j].value.i))
+ || ((ec[i][j].op == EDG_WLL_QUERY_OP_LESS) && (e->any.source < ec[i][j].value.i))
+ || ((ec[i][j].op == EDG_WLL_QUERY_OP_GREATER) && (e->any.source < ec[i][j].value.i))
+ || ( (ec[i][j].op == EDG_WLL_QUERY_OP_WITHIN)
+ && (e->any.source >= ec[i][j].value.i)
+ && (e->any.source <= ec[i][j].value2.i)) )
+ break;
+ }
+ else if ( ec[i][j].attr == EDG_WLL_QUERY_ATTR_LEVEL )
+ {
+ if ( ((ec[i][j].op == EDG_WLL_QUERY_OP_EQUAL) && (e->any.level == ec[i][j].value.i))
+ || ((ec[i][j].op == EDG_WLL_QUERY_OP_LESS) && (e->any.level < ec[i][j].value.i))
+ || ((ec[i][j].op == EDG_WLL_QUERY_OP_GREATER) && (e->any.level < ec[i][j].value.i))
+ || ( (ec[i][j].op == EDG_WLL_QUERY_OP_WITHIN)
+ && (e->any.level >= ec[i][j].value.i)
+ && (e->any.level <= ec[i][j].value2.i)) )
+ break;
+ }
+ else if ( ec[i][j].attr == EDG_WLL_QUERY_ATTR_HOST )
+ {
+ if ( !strcmp(ec[i][j].value.c, e->any.host) )
+ break;
+ }
+ else if ( ec[i][j].attr == EDG_WLL_QUERY_ATTR_EVENT_TYPE )
+ {
+ if ( e->any.type == ec[i][j].value.i )
+ break;
+ }
+ else if ( ec[i][j].attr == EDG_WLL_QUERY_ATTR_USERTAG )
+ {
+ if ( !strcmp(ec[i][j].attr_id.tag,e->userTag.name)
+ && cmp_string(e->userTag.value,ec[i][j].op,ec[i][j].value.c))
+ break;
+ }
+ else if ( ec[i][j].attr == EDG_WLL_QUERY_ATTR_INSTANCE )
+ {
+ if ( e->any.src_instance
+ && cmp_string(ec[i][j].value.c, ec[i][j].op, e->any.src_instance) )
+ break;
+ }
+ }
+ if ( !ec[i][j].attr )
+ /*
+ * No condition in "or" clause is valid
+ */
+ return 0;
+ }
+
+ return 1;
+}
+
+/* XXX: has to match exactly the main query in edg_wll_QueryEvents
+ * and similar one in srv_purge.c
+ */
+int convert_event_head(edg_wll_Context ctx,char **f,edg_wll_Event *e)
+{
+ int ret,i;
+
+ memset(e,0,sizeof *e);
+ edg_wll_ResetError(ctx);
+
+
+ if ((ret=edg_wlc_JobIdParse(f[0],&e->any.jobId))) {
+ edg_wll_SetError(ctx,-ret,"edg_wlc_JobIdParse()");
+ goto err;
+ }
+
+ e->type = atoi(f[1]);
+ free(f[1]); f[1] = NULL;
+
+ e->any.source = edg_wll_StringToSource(f[2]);
+ free(f[2]); f[2] = NULL;
+
+ e->any.host = f[3];
+ f[3] = NULL;
+
+ e->any.user = f[4];
+ f[4] = NULL;
+
+ e->any.timestamp.tv_sec = edg_wll_DBToTime(f[5]);
+ free(f[5]); f[5] = NULL;
+
+ e->any.timestamp.tv_usec = atoi(f[6]);
+ free(f[6]); f[6] = NULL;
+
+ e->any.level = atoi(f[7]);
+ free(f[7]); f[7] = NULL;
+
+ e->any.arrived.tv_sec = edg_wll_DBToTime(f[8]);
+ e->any.arrived.tv_usec = 0;
+ free(f[8]); f[8] = NULL;
+
+ return 0;
+
+err:
+ edg_wll_FreeEvent(e);
+ memset(e,0,sizeof *e);
+ for (i=0; i<9; i++) free(f[i]);
+ return edg_wll_Error(ctx,NULL,NULL);
+}
+
+
+
+/* FIXME: other op's, ORed conditions */
+int match_status(edg_wll_Context ctx, const edg_wll_JobStat *stat, const edg_wll_QueryRec **conds)
+{
+ int i, j, n;
+ char *s, *s1;
+
+
+ if ( !conds ) return 1;
+
+ for ( i = 0; conds[i]; i++ )
+ {
+ for ( j = 0; conds[i][j].attr; j++ )
+ {
+ if ( is_indexed(&(conds[i][j]), ctx) ) goto or_satisfied;
+
+ switch ( conds[i][j].attr )
+ {
+ case EDG_WLL_QUERY_ATTR_STATUS:
+ switch ( conds[i][j].op )
+ {
+ case EDG_WLL_QUERY_OP_EQUAL:
+ if ( conds[i][j].value.i == stat->state ) goto or_satisfied;
+ break;
+ case EDG_WLL_QUERY_OP_UNEQUAL:
+ if ( conds[i][j].value.i != stat->state ) goto or_satisfied;
+ break;
+ case EDG_WLL_QUERY_OP_LESS:
+ if ( conds[i][j].value.i > stat->state ) goto or_satisfied;
+ break;
+ case EDG_WLL_QUERY_OP_GREATER:
+ if ( conds[i][j].value.i < stat->state ) goto or_satisfied;
+ break;
+ case EDG_WLL_QUERY_OP_WITHIN:
+ if ( conds[i][j].value.i <= stat->state
+ && conds[i][j].value2.i >= stat->state ) goto or_satisfied;
+ break;
+ }
+ break;
+ case EDG_WLL_QUERY_ATTR_RESUBMITTED:
+ if ( conds[i][j].op == EDG_WLL_QUERY_OP_EQUAL ) {
+ if ( conds[i][j].value.i == stat->resubmitted ) goto or_satisfied;
+ } else if ( conds[i][j].op == EDG_WLL_QUERY_OP_UNEQUAL )
+ if ( conds[i][j].value.i != stat->resubmitted ) goto or_satisfied;
+ break;
+ case EDG_WLL_QUERY_ATTR_DONECODE:
+ switch ( conds[i][j].op )
+ {
+ case EDG_WLL_QUERY_OP_EQUAL:
+ if ( conds[i][j].value.i == stat->done_code ) goto or_satisfied;
+ break;
+ case EDG_WLL_QUERY_OP_UNEQUAL:
+ if ( conds[i][j].value.i != stat->done_code ) goto or_satisfied;
+ break;
+ case EDG_WLL_QUERY_OP_LESS:
+ if ( conds[i][j].value.i > stat->done_code ) goto or_satisfied;
+ break;
+ case EDG_WLL_QUERY_OP_GREATER:
+ if ( conds[i][j].value.i < stat->done_code ) goto or_satisfied;
+ break;
+ case EDG_WLL_QUERY_OP_WITHIN:
+ if ( conds[i][j].value.i <= stat->done_code
+ && conds[i][j].value2.i >= stat->done_code ) goto or_satisfied;
+ break;
+ }
+ break;
+ case EDG_WLL_QUERY_ATTR_EXITCODE:
+ switch ( conds[i][j].op )
+ {
+ case EDG_WLL_QUERY_OP_EQUAL:
+ if ( conds[i][j].value.i == stat->exit_code ) goto or_satisfied;
+ break;
+ case EDG_WLL_QUERY_OP_UNEQUAL:
+ if ( conds[i][j].value.i != stat->exit_code ) goto or_satisfied;
+ break;
+ case EDG_WLL_QUERY_OP_LESS:
+ if ( conds[i][j].value.i > stat->exit_code ) goto or_satisfied;
+ break;
+ case EDG_WLL_QUERY_OP_GREATER:
+ if ( conds[i][j].value.i < stat->exit_code ) goto or_satisfied;
+ break;
+ case EDG_WLL_QUERY_OP_WITHIN:
+ if ( conds[i][j].value.i <= stat->exit_code
+ && conds[i][j].value2.i >= stat->exit_code ) goto or_satisfied;
+ break;
+ }
+ break;
+ case EDG_WLL_QUERY_ATTR_OWNER:
+ if (stat->owner) {
+ if (conds[i][j].value.c) {
+ if (!strcmp(conds[i][j].value.c, stat->owner) ) {
+ if ( conds[i][j].op == EDG_WLL_QUERY_OP_EQUAL ) goto or_satisfied;
+ } else if ( conds[i][j].op == EDG_WLL_QUERY_OP_UNEQUAL ) goto or_satisfied;
+ } else if (ctx->peerName) {
+ if (!strcmp(ctx->peerName, stat->owner) ) {
+ if ( conds[i][j].op == EDG_WLL_QUERY_OP_EQUAL ) goto or_satisfied;
+ } else if ( conds[i][j].op == EDG_WLL_QUERY_OP_UNEQUAL ) goto or_satisfied;
+ }
+ }
+ break;
+ case EDG_WLL_QUERY_ATTR_LOCATION:
+ if ( stat->location )
+ {
+ if ( !strcmp(conds[i][j].value.c, stat->location) ) {
+ if ( conds[i][j].op == EDG_WLL_QUERY_OP_EQUAL ) goto or_satisfied;
+ } else if ( conds[i][j].op == EDG_WLL_QUERY_OP_UNEQUAL ) goto or_satisfied;
+ }
+ break;
+ case EDG_WLL_QUERY_ATTR_DESTINATION:
+ if ( stat->destination )
+ {
+ if ( !strcmp(conds[i][j].value.c, stat->destination) ) {
+ if ( conds[i][j].op == EDG_WLL_QUERY_OP_EQUAL ) goto or_satisfied;
+ } else if ( conds[i][j].op == EDG_WLL_QUERY_OP_UNEQUAL ) goto or_satisfied;
+ }
+ break;
+ case EDG_WLL_QUERY_ATTR_JOBID:
+ if ( !stat->jobId )
+ break;
+ s = edg_wlc_JobIdUnparse(stat->jobId);
+ s1 = edg_wlc_JobIdUnparse(conds[i][j].value.j);
+ if ( s && s1 )
+ {
+ int r = strcmp(s1, s);
+ free(s); free(s1);
+ if ( !r ) {
+ if ( conds[i][j].op == EDG_WLL_QUERY_OP_EQUAL ) goto or_satisfied;
+ } else if ( conds[i][j].op == EDG_WLL_QUERY_OP_UNEQUAL ) goto or_satisfied;
+ }
+ break;
+ case EDG_WLL_QUERY_ATTR_PARENT:
+ if ( !stat->parent_job )
+ break;
+ s = edg_wlc_JobIdUnparse(stat->parent_job);
+ s1 = edg_wlc_JobIdUnparse(conds[i][j].value.j);
+ if ( s && s1 )
+ {
+ int r = strcmp(s1, s);
+ free(s); free(s1);
+ if ( !r ) {
+ if ( conds[i][j].op == EDG_WLL_QUERY_OP_EQUAL ) goto or_satisfied;
+ } else if ( conds[i][j].op == EDG_WLL_QUERY_OP_UNEQUAL ) goto or_satisfied;
+ }
+ break;
+ case EDG_WLL_QUERY_ATTR_USERTAG:
+ if ( !stat->user_tags )
+ {
+ if ( conds[i][j].op == EDG_WLL_QUERY_OP_UNEQUAL )
+ goto or_satisfied;
+
+ break;
+ }
+ for ( n = 0; stat->user_tags[n].tag; n++ )
+ if ( !strcasecmp(conds[i][j].attr_id.tag, stat->user_tags[n].tag) )
+ {
+ if ( !strcmp(conds[i][j].value.c, stat->user_tags[n].value) ) {
+ if ( conds[i][j].op == EDG_WLL_QUERY_OP_EQUAL ) goto or_satisfied;
+ } else if ( conds[i][j].op == EDG_WLL_QUERY_OP_UNEQUAL ) goto or_satisfied;
+
+ break;
+ }
+ if ( !stat->user_tags[n].tag && conds[i][j].op == EDG_WLL_QUERY_OP_UNEQUAL )
+ goto or_satisfied;
+ break;
+ case EDG_WLL_QUERY_ATTR_TIME:
+ if ( !stat->stateEnterTimes || !stat->stateEnterTimes[1+conds[i][j].attr_id.state] )
+ break;
+ switch ( conds[i][j].op )
+ {
+ case EDG_WLL_QUERY_OP_EQUAL:
+ if ( conds[i][j].value.t.tv_sec == stat->stateEnterTimes[1+conds[i][j].attr_id.state] ) goto or_satisfied;
+ break;
+ case EDG_WLL_QUERY_OP_UNEQUAL:
+ if ( conds[i][j].value.t.tv_sec != stat->stateEnterTimes[1+conds[i][j].attr_id.state] ) goto or_satisfied;
+ break;
+ case EDG_WLL_QUERY_OP_LESS:
+ if ( conds[i][j].value.t.tv_sec > stat->stateEnterTimes[1+conds[i][j].attr_id.state] ) goto or_satisfied;
+ break;
+ case EDG_WLL_QUERY_OP_GREATER:
+ if ( conds[i][j].value.t.tv_sec < stat->stateEnterTimes[1+conds[i][j].attr_id.state] ) goto or_satisfied;
+ break;
+ case EDG_WLL_QUERY_OP_WITHIN:
+ if ( conds[i][j].value.t.tv_sec <= stat->stateEnterTimes[1+conds[i][j].attr_id.state]
+ && conds[i][j].value2.t.tv_sec >= stat->stateEnterTimes[1+conds[i][j].attr_id.state] ) goto or_satisfied;
+ break;
+ }
+ break;
+ default:
+ break;
+ }
+ }
+
+ /*
+ * No one condition in "or clause satisfied
+ */
+ return 0;
+
+or_satisfied:
+ // just for escaping from nested cycles
+ ; /* prevent compiler to complain */
+ }
+
+ return 1;
+}
+
+static int cmp_string(const char *s1,edg_wll_QueryOp op,const char *s2)
+{
+ switch (op) {
+ case EDG_WLL_QUERY_OP_EQUAL: return !strcmp(s1,s2);
+ case EDG_WLL_QUERY_OP_LESS: return strcmp(s1,s2)<0;
+ case EDG_WLL_QUERY_OP_GREATER: return strcmp(s1,s2)>0;
+ default: return 0;
+ }
+ return 0;
+}
+
+
+int check_strict_jobid(edg_wll_Context ctx, const edg_wlc_JobId job)
+{
+ char *job_host;
+ unsigned int job_port;
+
+ edg_wll_ResetError(ctx);
+
+ /* Allow all jobids when server name is not set. */
+ if (ctx->srvName == NULL) return edg_wll_Error(ctx,NULL,NULL);
+
+ edg_wlc_JobIdGetServerParts(job,&job_host,&job_port);
+
+ if (strcasecmp(job_host,ctx->srvName) || job_port != ctx->srvPort)
+ {
+ char *jobid,msg[300];
+
+ jobid = edg_wlc_JobIdUnparse(job);
+ snprintf(msg,sizeof msg,"%s: does not match server address",jobid);
+ msg[sizeof msg - 1] = 0;
+ edg_wll_SetError(ctx,EINVAL,msg);
+ free(jobid);
+ }
+
+ free(job_host);
+ return edg_wll_Error(ctx,NULL,NULL);
+}
+
+static int check_strict_jobid_cond(edg_wll_Context ctx, const edg_wll_QueryRec **cond)
+{
+ int i,j,ret;
+
+ if (!cond) return edg_wll_ResetError(ctx);
+ for (i=0; cond[i]; i++) for (j=0; cond[i][j].attr; j++)
+ if (cond[i][j].attr == EDG_WLL_QUERY_ATTR_JOBID &&
+ (ret = check_strict_jobid(ctx,cond[i][j].value.j)))
+ return ret;
+
+ return 0;
+}
+
+static int is_all_query(const edg_wll_QueryRec **jc)
+{
+ if (!jc || !*jc) return 1;
+
+ if (jc[0][0].attr == EDG_WLL_QUERY_ATTR_OWNER &&
+ jc[0][0].op == EDG_WLL_QUERY_OP_EQUAL &&
+ !jc[0][1].attr && !jc[1]) return 1;
+
+ return 0;
+}
--- /dev/null
+int convert_event_head(edg_wll_Context,char **,edg_wll_Event *);
+int check_strict_jobid(edg_wll_Context, const edg_wlc_JobId);
+int match_status(edg_wll_Context, const edg_wll_JobStat *stat,const edg_wll_QueryRec **conditions);
--- /dev/null
+#ident "$Header$"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "glite/lb/il_string.h"
+#include "glite/lb/context-int.h"
+
+#include "store.h"
+
+#ifdef __GNUC__
+#define UNUSED_VAR __attribute__((unused))
+#else
+#define UNUSED_VAR
+#endif
+
+int
+handle_request(edg_wll_Context ctx,char *buf, int len UNUSED_VAR)
+{
+ char *p = buf;
+ char *event, *ucs;
+ int ret;
+
+ edg_wll_ResetError(ctx);
+
+ p = get_string(p, &ucs);
+ if(p == NULL) return edg_wll_SetError(ctx,EDG_WLL_IL_PROTO,"reading UCS");
+
+ p = get_string(p, &event);
+ if(p == NULL) {
+ edg_wll_SetError(ctx,EDG_WLL_IL_PROTO,"reading event string");
+ if(ucs) free(ucs);
+ return EDG_WLL_IL_PROTO;
+ }
+
+ ret = db_store(ctx,ucs, event);
+
+ if(ucs)
+ free(ucs);
+ if(event)
+ free(event);
+
+ return(ret);
+}
+
+
+int
+create_reply(const edg_wll_Context ctx,char *buf, int max_len)
+{
+ int len, err_code, err_code_min;
+ char *p;
+ char *err_msg;
+
+ err_code_min = 0;
+
+ switch(edg_wll_Error(ctx,NULL,&err_msg)) {
+
+ case 0:
+ err_code = LB_OK;
+ break;
+
+ case ENOMEM:
+ err_code = LB_NOMEM;
+ break;
+
+ case EDG_WLL_IL_PROTO:
+ err_code = LB_PROTO;
+ break;
+
+ default:
+ err_code = LB_DBERR;
+ err_code_min = edg_wll_Error(ctx,NULL,NULL);
+ break;
+
+ }
+
+ if (!err_msg) err_msg=strdup("OK");
+
+ len = 17 + len_int(err_code) + len_int(err_code_min) + len_string(err_msg);
+ if(len > max_len) {
+ free(err_msg);
+ return(0);
+ }
+
+ snprintf(buf, max_len, "%16d\n", len - 17);
+ p = buf + 17;
+ p = put_int(p, err_code);
+ p = put_int(p, err_code_min);
+ p = put_string(p, err_msg);
+ free(err_msg);
+
+ return(len);
+}
+
+
--- /dev/null
+#ident "$Header$"
+
+#include "glite/lb/trio.h"
+#include "glite/lb/context-int.h"
+
+#include "lbs_db.h"
+#include "server_state.h"
+
+int edg_wll_GetServerState(edg_wll_Context ctx,const char *name,char **val)
+{
+ char *stmt = NULL;
+ edg_wll_Stmt q = NULL;
+
+
+ trio_asprintf(&stmt,"select value from server_state "
+ "where prefix = 'https://%|Ss:%d' and name = '%|Ss'",
+ ctx->srvName,ctx->srvPort,name);
+
+ switch (edg_wll_ExecStmt(ctx,stmt,&q)) {
+ case 0: edg_wll_SetError(ctx,ENOENT,name); break;
+ case -1: break;
+ default: edg_wll_FetchRow(q,val); break;
+ }
+
+ edg_wll_FreeStmt(&q);
+ free(stmt);
+ return edg_wll_Error(ctx,NULL,NULL);
+}
+
+int edg_wll_SetServerState(edg_wll_Context ctx,const char *name,const char *val)
+{
+ char *stmt = NULL;
+
+ trio_asprintf(&stmt,"insert into server_state (prefix,name,value) "
+ "values ('https://%|Ss:%d','%|Ss','%|Ss')",
+ ctx->srvName,ctx->srvPort,name,val);
+
+ switch(edg_wll_ExecStmt(ctx,stmt,NULL)) {
+ case 1: break;
+ case -1: if (edg_wll_Error(ctx,NULL,NULL) == EEXIST) {
+ free(stmt);
+ trio_asprintf(&stmt,"update server_state set value = '%|Ss' "
+ "where prefix = 'https://%|Ss:%d' "
+ "and name = '%|Ss'",
+ val,ctx->srvName,ctx->srvPort,name);
+ edg_wll_ExecStmt(ctx,stmt,NULL);
+ }
+ break;
+
+ default: abort();
+ }
+ free(stmt);
+ return edg_wll_Error(ctx,NULL,NULL);
+}
--- /dev/null
+#ifndef _EDG_WORKLOAD_LOGGING_LBSERVER_H_
+#define EDG_WLL_STATE_DUMP_START "StartDump"
+#define EDG_WLL_STATE_DUMP_END "EndDump"
+
+#ident "$Header$"
+
+int edg_wll_GetServerState(edg_wll_Context,const char *,char **);
+int edg_wll_SetServerState(edg_wll_Context,const char *,const char *);
+
+#endif
--- /dev/null
+#ident "$Header$"
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <syslog.h>
+#include <assert.h>
+#include <string.h>
+#include <time.h>
+
+#include "glite/wms/jobid/cjobid.h"
+
+#include "glite/lb/trio.h"
+#include "glite/lb/context.h"
+#include "glite/lb/events_parse.h"
+#include "glite/lb/mini_http.h"
+#include "glite/lb/ulm_parse.h"
+
+#include "lb_html.h"
+#include "lb_proto.h"
+#include "store.h"
+#include "lock.h"
+#include "lbs_db.h"
+#include "query.h"
+#include "get_events.h"
+#include "glite/lb/purge.h"
+#include "glite/lb/load.h"
+#include "glite/lb/dump.h"
+#include "purge.h"
+#include "lb_xml_parse.h"
+
+
+#define DUMP_FILE_STORAGE "/tmp/"
+
+#define sizofa(a) (sizeof(a)/sizeof((a)[0]))
+
+static const char* const resp_headers[] = {
+ "Cache-Control: no-cache",
+ "Accept: application/x-dglb",
+ "User-Agent: edg_wll_Server/" PROTO_VERSION "/" COMP_PROTO,
+ "Content-Type: application/x-dglb",
+ NULL
+};
+
+static int purge_one(edg_wll_Context ctx,const edg_wlc_JobId,int,int);
+
+int edg_wll_CreateTmpFileStorage(edg_wll_Context ctx, char *prefix, char **fname)
+{
+ char fname_buf[1024];
+ struct timeval tv;
+ int retfd;
+
+
+ while ( 1 )
+ {
+ gettimeofday(&tv, NULL);
+ snprintf(fname_buf, 1024, "%s/%ld_%ld", prefix, tv.tv_sec, tv.tv_usec);
+
+ if ( (retfd = open(fname_buf, O_WRONLY|O_CREAT|O_EXCL|O_APPEND,0600)) == -1 )
+ {
+ if ( errno != EEXIST )
+ {
+ char buff[100];
+
+ sprintf(buff, "couldn't create temporary server file");
+ return edg_wll_SetError(ctx, errno, buff);
+ }
+ }
+ else
+ break;
+ }
+
+ *fname = strdup(fname_buf);
+
+ return retfd;
+}
+
+int edg_wll_CreateFileStorageFromTmp(edg_wll_Context ctx, char *old_file, char *file_type, char **fname)
+{
+ char fname_buf[1024],
+ fname_prefix[1024],
+ stimebuf[100];
+ char *stmp;
+ struct timeval tv;
+ int retfd;
+
+
+ if ( (stmp = strrchr(old_file, '/')) )
+ {
+ strncpy(fname_prefix, old_file, stmp - old_file);
+ fname_prefix[stmp - old_file] = '\0';
+ }
+
+ while ( 1 )
+ {
+ gettimeofday(&tv, NULL);
+ edg_wll_ULMTimevalToDate(tv.tv_sec, tv.tv_usec, stimebuf);
+ snprintf(fname_buf, 1024, "%s/%s_%s", fname_prefix, file_type, stimebuf);
+
+ if ( !link(old_file, fname_buf) )
+ break;
+
+ if ( errno != EEXIST )
+ {
+ char buff[100];
+
+ sprintf(buff, "couldn't create server %s file", file_type);
+ return edg_wll_SetError(ctx, errno, buff);
+ }
+ }
+
+ *fname = strdup(fname_buf);
+
+ return retfd;
+}
+
+int edg_wll_CreateFileStorage(edg_wll_Context ctx, char *file_type, char *prefix, char **fname)
+{
+ char fname_buf[1024],
+ stimebuf[100];
+ struct timeval tv;
+ int retfd;
+
+ if ( *fname )
+ {
+ snprintf(fname_buf, 1024, "%s/%s", prefix? prefix: "", *fname);
+ if ( (retfd = open(*fname, O_WRONLY|O_CREAT|O_EXCL|O_APPEND,0600)) == -1 )
+ {
+ char buff[100];
+ if ( errno == EEXIST )
+ sprintf(buff, "Server file %s exist", fname_buf);
+ else
+ sprintf(buff, "Server couldn't create file %s", fname_buf);
+ edg_wll_SetError(ctx, errno, buff);
+
+ return -1;
+ }
+ if ( prefix )
+ {
+ free(*fname);
+ *fname = strdup(fname_buf);
+ }
+
+ return retfd;
+ }
+
+ while ( 1 )
+ {
+ gettimeofday(&tv, NULL);
+ edg_wll_ULMTimevalToDate(tv.tv_sec, tv.tv_usec, stimebuf);
+ if ( !prefix )
+ {
+ if ( strcmp(file_type,FILE_TYPE_PURGE) == 0 )
+ prefix = ctx->purgeStorage;
+ else if ( strcmp(file_type,FILE_TYPE_DUMP) == 0 )
+ prefix = ctx->dumpStorage;
+ else
+ prefix = "";
+ }
+ snprintf(fname_buf, 1024, "%s/%s_%s", prefix, file_type, stimebuf);
+
+ if ( (retfd = open(fname_buf, O_WRONLY|O_CREAT|O_EXCL|O_APPEND,0600)) == -1 )
+ {
+ if ( errno != EEXIST )
+ {
+ char buff[100];
+
+ sprintf(buff, "couldn't create server %s file", file_type);
+ edg_wll_SetError(ctx, errno, buff);
+
+ return -1;
+ }
+ }
+ else
+ break;
+ }
+
+ *fname = strdup(fname_buf);
+
+ return retfd;
+}
+
+int edg_wll_PurgeServer(edg_wll_Context ctx,const edg_wll_PurgeRequest *request)
+{
+ int i,parse = 0,dumpfile = -1;
+ edg_wlc_JobId job;
+ char *message = NULL, *response = NULL;
+ char *tmpfname;
+ int naffected_jobs = 0;
+ edg_wll_PurgeResult result;
+ int ret = HTTP_OK;
+
+
+ if (!ctx->noAuth) {
+ edg_wll_SetError(ctx,EPERM,"only superusers may purge");
+ goto abort;
+ }
+
+ edg_wll_ResetError(ctx);
+ memset(&result, 0, sizeof(edg_wll_PurgeResult));
+
+
+ if ( (request->flags & EDG_WLL_PURGE_SERVER_DUMP) &&
+ ((dumpfile = edg_wll_CreateTmpPurgeFile(ctx, &tmpfname)) == -1 ) )
+ return edg_wll_Error(ctx, NULL, NULL);
+
+ if (request->flags&EDG_WLL_PURGE_REALLY_PURGE) {
+ edg_wll_DumpRequest req = {
+ EDG_WLL_DUMP_LAST_END, EDG_WLL_DUMP_NOW
+ };
+ edg_wll_DumpResult res;
+
+ if (edg_wll_DumpEvents(ctx,&req,&res))
+ {
+ if ( request->flags & EDG_WLL_PURGE_SERVER_DUMP )
+ unlink(tmpfname);
+ return edg_wll_Error(ctx, NULL, NULL);
+ }
+ }
+
+ if (request->jobs) for (i=0; request->jobs[i]; i++) {
+ if (edg_wlc_JobIdParse(request->jobs[i],&job)) {
+ fprintf(stderr,"%s: parse error\n",request->jobs[i]);
+ parse = 1;
+ }
+ else {
+ if (check_strict_jobid(ctx,job)) {
+ fprintf(stderr,"%s: not my job\n",request->jobs[i]);
+ parse = 1;
+ }
+ else {
+ switch (purge_one(ctx,job,dumpfile,request->flags&EDG_WLL_PURGE_REALLY_PURGE)) {
+ case 0: if (request->flags & EDG_WLL_PURGE_LIST_JOBS) {
+ result.jobs = realloc(result.jobs,(naffected_jobs+2) * sizeof(*result.jobs));
+ result.jobs[naffected_jobs] = strdup(request->jobs[i]);
+ result.jobs[naffected_jobs+1] = NULL;
+ }
+ naffected_jobs++;
+ break;
+ case ENOENT: parse = 1;
+ edg_wll_ResetError(ctx);
+ break;
+ default: goto abort;
+ }
+
+ }
+ edg_wlc_JobIdFree(job);
+ }
+ }
+ else {
+ edg_wll_Stmt s;
+ char *job_s;
+ int res;
+ time_t timeout[EDG_WLL_NUMBER_OF_STATCODES],
+ now = time(NULL);
+
+ for (i=0; i<EDG_WLL_NUMBER_OF_STATCODES; i++)
+ timeout[i] = request->timeout[i] < 0 ? ctx->purge_timeout[i] : request->timeout[i];
+
+ if (edg_wll_ExecStmt(ctx,"select dg_jobid from jobs",&s) < 0) goto abort;
+ while ((res = edg_wll_FetchRow(s,&job_s)) > 0) {
+ if (edg_wlc_JobIdParse(job_s,&job)) {
+ fprintf(stderr,"%s: parse error (internal inconsistency !)\n",job_s);
+ parse = 1;
+ }
+ else {
+ edg_wll_JobStat stat;
+
+ if (check_strict_jobid(ctx,job)) {
+ edg_wlc_JobIdFree(job);
+ free(job_s);
+ parse = 1;
+ continue;
+ }
+
+ memset(&stat,0,sizeof stat);
+ if (edg_wll_JobStatus(ctx,job,0,&stat)) goto abort; /* XXX: memory leak */
+
+ switch (stat.state) {
+ case EDG_WLL_JOB_CLEARED:
+ case EDG_WLL_JOB_ABORTED:
+ case EDG_WLL_JOB_CANCELLED:
+ i = stat.state;
+ break;
+ default:
+ i = EDG_WLL_PURGE_JOBSTAT_OTHER;
+ }
+
+ if (now-stat.lastUpdateTime.tv_sec > timeout[i] && !check_strict_jobid(ctx,job))
+ {
+ if (purge_one(ctx,job,dumpfile,request->flags&EDG_WLL_PURGE_REALLY_PURGE))
+ goto abort;
+
+ /* XXX: change with the streaming interface */
+ if (request->flags & EDG_WLL_PURGE_LIST_JOBS) {
+ result.jobs = realloc(result.jobs,(naffected_jobs+2) * sizeof(*result.jobs));
+ result.jobs[naffected_jobs] = job_s;
+ result.jobs[naffected_jobs+1] = NULL;
+ job_s = NULL;
+ }
+ naffected_jobs++;
+ }
+
+ edg_wlc_JobIdFree(job);
+ edg_wll_FreeStatus(&stat);
+ free(job_s);
+ }
+ }
+ edg_wll_FreeStmt(&s);
+abort:
+ // just for escaping from nested cycles
+ ; /* prevent compiler to complain */
+ }
+
+ if (parse && !edg_wll_Error(ctx,NULL,NULL))
+ {
+ if ( naffected_jobs )
+ edg_wll_SetError(ctx,EINVAL,"Invalid JobId(s) but other jobs purged");
+ else
+ edg_wll_SetError(ctx,EINVAL,"Invalid JobId(s)");
+ }
+
+ switch ( edg_wll_Error(ctx,NULL,NULL) )
+ {
+ case 0:
+ ret = HTTP_OK;
+ break;
+ case EINVAL:
+ ret = HTTP_INVALID;
+ break;
+ case EPERM:
+ ret = HTTP_UNAUTH;
+ break;
+
+ /* fatal errors */
+ case ENOMEM:
+ /* fall through */
+ default:
+ ret = HTTP_INTERNAL;
+ break;
+ }
+
+ if (ret != HTTP_INTERNAL) {
+ if ( request->flags & EDG_WLL_PURGE_SERVER_DUMP )
+ {
+ edg_wll_CreatePurgeFileFromTmp(ctx, tmpfname, &(result.server_file));
+ unlink(tmpfname);
+ }
+
+ if ( edg_wll_PurgeResultToXML(ctx, &result, &message) )
+ ret = HTTP_INTERNAL;
+ else
+ printf("%s", message);
+ }
+
+ if ( result.server_file )
+ free(result.server_file);
+ if ( result.jobs )
+ {
+ for ( i = 0; result.jobs[i]; i++ )
+ free(result.jobs[i]);
+ free(result.jobs);
+ }
+
+ asprintf(&response, "HTTP/1.1 %d %s", ret, edg_wll_HTTPErrorMessage(ret));
+
+ edg_wll_http_send(ctx, response, resp_headers, message);
+
+ return edg_wll_Error(ctx,NULL,NULL);
+}
+
+static void unlock_and_check(edg_wll_Context ctx,edg_wlc_JobId job)
+{
+ char *job_s,*et,*ed;
+
+ if (edg_wll_UnlockJob(ctx,job)) {
+ job_s = edg_wlc_JobIdUnparse(job);
+
+ edg_wll_Error(ctx,&et,&ed);
+ fprintf(stderr,"%s: edg_wll_UnlockJob(): %s (%s) -- expect bogus things\n",
+ job_s,et,ed);
+ syslog(LOG_CRIT,"%s: edg_wll_UnlockJob(): %s (%s) -- expect bogus things",
+ job_s,et,ed);
+ free(et); free(ed); free(job_s);
+ }
+}
+
+
+int purge_one(edg_wll_Context ctx,const edg_wlc_JobId job,int dump, int purge)
+{
+ char *dbjob;
+ char *stmt = NULL;
+ edg_wll_Stmt q;
+ int ret,dumped = 0;
+
+ edg_wll_ResetError(ctx);
+ if ( !purge && dump < 0 ) return 0;
+
+ dbjob = edg_wlc_JobIdGetUnique(job); /* XXX: strict jobid already checked */
+ if (edg_wll_LockJob(ctx,job)) goto clean;
+
+ if ( purge )
+ {
+ trio_asprintf(&stmt,"delete from jobs where jobid = '%|Ss'",dbjob);
+ ret = edg_wll_ExecStmt(ctx,stmt,NULL);
+ if (ret <= 0) {
+ unlock_and_check(ctx,job);
+ if (ret == 0) {
+ fprintf(stderr,"%s: no such job\n",dbjob);
+ edg_wll_SetError(ctx,ENOENT,dbjob);
+ }
+ goto clean;
+ }
+ free(stmt); stmt = NULL;
+
+ trio_asprintf(&stmt,"delete from states where jobid = '%|Ss'",dbjob);
+ if (edg_wll_ExecStmt(ctx,stmt,NULL) < 0) {
+ unlock_and_check(ctx,job);
+ goto clean;
+ }
+ free(stmt); stmt = NULL;
+
+/* Why on earth ?
+ trio_asprintf(&stmt,"delete from states where jobid = '%|Ss'",dbjob);
+ if (edg_wll_ExecStmt(ctx,stmt,NULL) < 0) {
+ unlock_and_check(ctx,job);
+ goto clean;
+ }
+ free(stmt); stmt = NULL;
+*/
+
+ }
+
+ if (!ctx->strict_locking) unlock_and_check(ctx,job);
+
+ if ( purge )
+ {
+ trio_asprintf(&stmt,"delete from status_tags where jobid = '%|Ss'",dbjob);
+ if (edg_wll_ExecStmt(ctx,stmt,NULL) < 0) goto unlock;
+ free(stmt); stmt = NULL;
+ }
+
+ if (dump >= 0)
+ trio_asprintf(&stmt,
+ "select event,code,prog,host,u.cert_subj,time_stamp,usec,level,arrived "
+ "from events e,users u "
+ "where e.jobid='%|Ss' "
+ "and u.userid=e.userid "
+ "order by event", dbjob);
+ else
+ trio_asprintf(&stmt,"select event from events "
+ "where jobid='%|Ss' "
+ "order by event", dbjob);
+
+/* check for events repeatedly -- new one may have arrived in the meantime */
+ while ((ret = edg_wll_ExecStmt(ctx,stmt,&q)) > 0) {
+ char *res[9];
+
+ dumped = 1;
+ while ((ret = edg_wll_FetchRow(q,res)) > 0) {
+ int event;
+
+ event = atoi(res[0]);
+ free(res[0]); res[0] = NULL;
+
+ if (dump >= 0) {
+ edg_wll_Event e;
+
+ assert(ret == 9);
+ res[0] = edg_wlc_JobIdUnparse(job);
+ if (convert_event_head(ctx,res,&e) || edg_wll_get_event_flesh(ctx,event,&e))
+ {
+ char *et,*ed;
+ int i;
+
+ /* Most likely sort of internal inconsistency.
+ * Must not be fatal -- just complain
+ */
+ edg_wll_Error(ctx,&et,&ed);
+ fprintf(stderr,"%s event %d: %s (%s)\n",dbjob,event,et,ed);
+ syslog(LOG_WARNING,"%s event %d: %s (%s)",dbjob,event,et,ed);
+ free(et); free(ed);
+ for (i=0; i<sizofa(res); i++) free(res[i]);
+ edg_wll_ResetError(ctx);
+ }
+ else {
+ char *event_s = edg_wll_UnparseEvent(ctx,&e);
+ char arr_s[100];
+ int len, written, total;
+
+ strcpy(arr_s, "DG.ARRIVED=");
+ edg_wll_ULMTimevalToDate(e.any.arrived.tv_sec,
+ e.any.arrived.tv_usec,
+ arr_s+strlen("DG.ARRIVED="));
+
+ len = strlen(arr_s);
+ total = 0;
+ while (total != len) {
+ written = write(dump,arr_s+total,len-total);
+ if (written < 0 && errno != EAGAIN) {
+ edg_wll_SetError(ctx,errno,"writing dump file");
+ free(event_s);
+ goto clean;
+ }
+ total += written;
+ }
+ write(dump, " ", 1);
+
+ len = strlen(event_s);
+ total = 0;
+ while (total != len) {
+ written = write(dump,event_s+total,len-total);
+ if (written < 0 && errno != EAGAIN) {
+ perror("dump to file");
+ syslog(LOG_ERR,"dump to file: %m");
+ dump = -1; /* XXX: likely to be a permanent error
+ * give up writing but do purge */
+ break;
+ }
+ total += written;
+ }
+ /* write(dump,"\n",1); edg_wll_UnparseEvent does so */
+ free(event_s);
+ }
+ edg_wll_FreeEvent(&e);
+ }
+
+ if ( purge ) {
+ if (edg_wll_delete_event(ctx,dbjob,event)) {
+ char *et,*ed;
+
+ /* XXX: just complain and carry on. Is it OK? */
+ edg_wll_Error(ctx,&et,&ed);
+ fprintf(stderr,"%s event %d: %s (%s)\n",dbjob,event,et,ed);
+ syslog(LOG_WARNING,"%s event %d: %s (%s)",dbjob,event,et,ed);
+ free(et); free(ed);
+ edg_wll_ResetError(ctx);
+ }
+ }
+ }
+ edg_wll_FreeStmt(&q);
+ if (ret < 0 || !purge) break;
+ }
+
+ edg_wll_FreeStmt(&q);
+ if (ret == 0 && dumped == 0) {
+ if (ctx->strict_locking) unlock_and_check(ctx,job);
+ fprintf(stderr,"%s: no events, i.e. no such job or internal inconsistency\n",dbjob);
+ edg_wll_SetError(ctx,ENOENT,dbjob);
+ goto clean;
+ }
+
+unlock:
+ if (ctx->strict_locking) unlock_and_check(ctx,job);
+
+clean:
+ free(dbjob);
+ free(stmt);
+ return edg_wll_Error(ctx,NULL,NULL);
+}
--- /dev/null
+#ident "$Header$"
+
+/*
+
+@@@AUTO
+
+ * XXX: still lots of hardcoded stuff
+ * there's mapping db.column <-> event struct field
+ */
+
+@@@LANG: C
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+#include <errno.h>
+#include <syslog.h>
+
+#include <globus_config.h>
+
+#include "glite/wms/thirdparty/globus_ssl_utils/sslutils.h"
+#include "glite/wms/jobid/strmd5.h"
+
+#include "glite/lb/events_parse.h"
+#include "glite/lb/context-int.h"
+#include "glite/lb/producer.h"
+#include "glite/lb/log_proto.h" /* for EDG_WLL_LOG_USER_DEFAULT */
+#include "glite/lb/trio.h"
+
+#include "store.h"
+#include "get_events.h"
+#include "lbs_db.h"
+#include "lock.h"
+#include "lb_authz.h"
+
+static int store_user(edg_wll_Context,const char *,const char *);
+static int store_job(edg_wll_Context,const edg_wlc_JobId,const char *);
+static int store_flesh(edg_wll_Context,edg_wll_Event *,char *,int);
+static int store_seq(edg_wll_Context,edg_wll_Event *,int);
+static int check_dup(edg_wll_Context,edg_wll_Event *);
+static int check_auth(edg_wll_Context,edg_wll_Event *e);
+static int register_subjobs(edg_wll_Context,const edg_wll_RegJobEvent *);
+
+void edg_wll_StoreAnonymous(edg_wll_Context ctx,int anon) {
+ ctx->allowAnonymous = anon;
+}
+
+int edg_wll_StoreEvent(edg_wll_Context ctx,edg_wll_Event *e,int *seq)
+{
+ edg_wll_ErrorCode err = 0;
+ char *userid = NULL,*jobid,*stmt;
+ char *select_max,*ssrc;
+ edg_wll_Stmt sh = NULL;
+ int next = 0xDEAD;
+ char *now_s = NULL;
+
+ ssrc = jobid = stmt = select_max = NULL;
+
+ if ( ctx->event_load )
+ now_s = strdup(edg_wll_TimeToDB(e->any.arrived.tv_sec));
+ else
+ now_s = strdup(edg_wll_TimeToDB(time(NULL)));
+ edg_wll_ResetError(ctx);
+ switch (err = check_auth(ctx,e)) {
+ case 0: break;
+ case ENOENT: goto clean;
+ case EPERM:
+ if (!ctx->noAuth) goto clean;
+ edg_wll_ResetError(ctx);
+ break;
+ default: goto clean;
+ }
+ if ((err = check_dup(ctx,e))) goto clean;
+
+ userid = strdup(strmd5(e->any.user,NULL));
+
+/* make sure user record is there */
+ if ((err = store_user(ctx,userid,e->any.user))) goto clean;
+
+ jobid = edg_wlc_JobIdGetUnique(e->any.jobId);
+
+/* only REGJOB events determine job owner now */
+ if (e->type == EDG_WLL_EVENT_REGJOB &&
+ (err = store_job(ctx,e->any.jobId,userid))) goto clean;
+
+
+/* obtain next event sequence number */
+ trio_asprintf(&select_max,
+ "select max(event) from events "
+ "where jobid = '%|Ss'",jobid);
+
+ ssrc = edg_wll_SourceToString(e->any.source);
+
+/* try to insert (someone else may be doing the same) */
+ while (1) {
+ char *max;
+
+ if (edg_wll_ExecStmt(ctx,select_max,&sh) < 0 ||
+ edg_wll_FetchRow(sh,&max) < 0)
+ {
+ err = edg_wll_Error(ctx,NULL,NULL);
+ goto clean;
+ }
+ edg_wll_FreeStmt(&sh);
+
+ next = max && *max ? atoi(max)+1 : 0;
+
+ /* store an UNDEF event first in order to prevent race condition
+ * with readers */
+ trio_asprintf(&stmt,
+ "insert into events(jobid,event,code,prog,host,time_stamp,usec,arrived,level,userid) "
+ "values ('%|Ss',%d,%d,'%|Ss','%|Ss',%s,%d,'%|Ss',%d,'%|Ss')",
+ jobid,next,EDG_WLL_EVENT_UNDEF,ssrc,e->any.host,
+ edg_wll_TimeToDB(e->any.timestamp.tv_sec),e->any.timestamp.tv_usec,
+ now_s, e->any.level,userid);
+
+ if (edg_wll_ExecStmt(ctx,stmt,NULL) < 0) {
+ if ((err = edg_wll_Error(ctx,NULL,NULL)) != EEXIST)
+ goto clean;
+ } else break; /* successful insert */
+
+ /* we were late -- try once again */
+ free(stmt);
+ }
+
+ free(stmt);
+ if ((err = store_seq(ctx,e,next)) ||
+ (err = store_flesh(ctx,e,jobid,next))) {
+ /* attempt to cleanup, ignore new errors */
+ char *desc;
+ edg_wll_ErrorCode oerr = edg_wll_Error(ctx,NULL,&desc);
+
+ edg_wll_delete_event(ctx,jobid,next);
+ edg_wll_SetError(ctx,oerr,desc);
+ free(desc);
+ }
+ else {
+ /* emulate commit, i.e. swith to a real event type to make
+ * the record valid */
+ trio_asprintf(&stmt,
+ "update events set code=%d "
+ "where jobid='%|Ss' and event=%d",
+ (int) e->any.type,jobid,next);
+ switch (edg_wll_ExecStmt(ctx,stmt,NULL)) {
+ case 0: if (ctx->strict_locking)
+ err = edg_wll_SetError(ctx,ENOENT,"event disappeared on store while strict locking");
+ /* purge in progres: drop the garbage, ignore errors */
+ else {
+ edg_wll_delete_event(ctx,jobid,next);
+ err = edg_wll_SetError(ctx,ENOENT,"job being purged");
+ }
+ break;
+ case 1: if (ctx->strict_locking) err = 0;
+ else {
+ /* check whether the job is still there to prevent garbage
+ * left while there is a concurrent purge
+ */
+ free(stmt);
+ trio_asprintf(&stmt,
+ "select 'x' from jobs where jobid='%|Ss'",
+ jobid);
+ switch (edg_wll_ExecStmt(ctx,stmt,NULL)) {
+ case 1: break;
+ case 0: /* purge in progres */
+ edg_wll_delete_event(ctx,jobid,next);
+ err = edg_wll_SetError(ctx,ENOENT,"job being purged");
+ break;
+ default: err = edg_wll_SetError(ctx,EDG_WLL_ERROR_DB_CALL,
+ "more job records, what is that?");
+ break;
+ }
+ }
+ break;
+ case -1: err = edg_wll_Error(ctx,NULL,NULL);
+ break;
+
+ default: err = edg_wll_SetError(ctx,EDG_WLL_ERROR_DB_CALL,
+ "more event records, what is that?");
+ break;
+ }
+ }
+
+ if (err == 0 &&
+ e->any.type == EDG_WLL_EVENT_REGJOB &&
+ (e->regJob.jobtype == EDG_WLL_REGJOB_DAG ||
+ e->regJob.jobtype == EDG_WLL_REGJOB_PARTITIONED) &&
+ e->regJob.nsubjobs > 0) err = register_subjobs(ctx,&e->regJob);
+
+
+clean:
+ free(now_s);
+ free(userid);
+ free(jobid);
+ free(stmt);
+ free(ssrc);
+ free(select_max);
+ if (sh) edg_wll_FreeStmt(&sh);
+ if (!err && seq) *seq = next;
+ return err;
+}
+
+static int store_user(edg_wll_Context ctx,const char *userid,const char *subj)
+{
+ char *stmt;
+
+ trio_asprintf(&stmt,"insert into users(userid,cert_subj) "
+ "values ('%|Ss','%|Ss')",userid,subj);
+
+ if (edg_wll_ExecStmt(ctx,stmt,NULL) < 0) {
+ if (edg_wll_Error(ctx,NULL,NULL) == EEXIST)
+ edg_wll_ResetError(ctx);
+ }
+
+ free(stmt);
+ return edg_wll_Error(ctx,NULL,NULL);
+}
+
+static int store_job(edg_wll_Context ctx,const edg_wlc_JobId job,const char *userid)
+{
+ char *jobstr = edg_wlc_JobIdUnparse(job);
+ char *jobid = edg_wlc_JobIdGetUnique(job);
+ char *stmt;
+
+/* debug Duplicate key on index: Duplicate entry '(nil)' for key 1
+ */
+ if (jobid == NULL || jobstr == NULL)
+ return edg_wll_SetError(ctx,EINVAL,"store_job()");
+
+ edg_wll_ResetError(ctx);
+ trio_asprintf(&stmt,"insert into jobs(jobid,dg_jobid,userid) "
+ "values ('%|Ss','%|Ss','%|Ss')",jobid,jobstr,userid);
+
+ if (edg_wll_ExecStmt(ctx,stmt,NULL) < 0) {
+ if (edg_wll_Error(ctx,NULL,NULL) == EEXIST)
+ edg_wll_ResetError(ctx);
+ }
+ free(stmt);
+ free(jobstr);
+ free(jobid);
+ return edg_wll_Error(ctx,NULL,NULL);
+}
+
+/*
+ * XXX: store it in SHORT_FIELDS for now despite it should go to dedicated
+ * column in EVENTS.
+ *
+ * don't want to change the database structure now, will be done anyway
+ * soon
+ */
+static int store_seq(edg_wll_Context ctx,edg_wll_Event *e,int no)
+{
+ int ret;
+ char *stmt;
+ char *jobid = edg_wlc_JobIdGetUnique(e->any.jobId);
+
+ edg_wll_ResetError(ctx);
+ trio_asprintf(&stmt,"insert into short_fields(jobid,event,name,value) "
+ "values ('%|Ss',%d,'SEQCODE','%|Ss')",
+ jobid,no,e->any.seqcode);
+
+ ret = edg_wll_ExecStmt(ctx,stmt,NULL);
+ free(stmt);
+ free(jobid);
+
+ return ret>=0 ? 0 : edg_wll_Error(ctx,NULL,NULL);
+}
+
+#define SHORT_LEN 255 /* short_fiels.value db column lenght */
+
+static int store_flesh(edg_wll_Context ctx,edg_wll_Event *e,char *jobid,int no)
+{
+ struct {
+ char *key;
+ char *val;
+ } f[20];
+
+ char *stmt;
+ unsigned int i;
+ int err = 0;
+
+ edg_wll_ResetError(ctx);
+ memset(f,0,sizeof(f)); assert(f[0].key == NULL);
+
+ switch (e->type) {
+@@@{
+ for my $type (getTypesOrdered $event) {
+ next if $type eq '_common_';
+ selectType $event $type;
+ my $uctype = uc $type;
+ my $flctype = lcfirst $type;
+ gen qq{
+! case EDG_WLL_EVENT_$uctype:
+};
+ my $idx = 0;
+ for (getFieldsOrdered $event) {
+ my $f = selectField $event $_;
+ my $name = getName $f;
+ my $ucname = uc $name;
+ my $fucname = ucfirst $name;
+ my $tos = $f->{codes} ?
+ "f[$idx].val = edg_wll\_$type${fucname}ToString(e->$flctype.$name);" :
+ toString $f "e->$flctype.$name","f[$idx].val";
+ gen qq{
+! f[$idx].key = "$ucname";
+! $tos
+};
+ $idx++;
+ }
+ gen qq{
+! assert($idx<sizeof f/sizeof f[0]);
+! break;
+};
+ }
+@@@}
+ default:
+ break;
+ }
+
+ for (i=0; i<sizeof(f)/sizeof(f[0]) && !err; i++) if (f[i].key && f[i].val) {
+ trio_asprintf(&stmt,"insert into %s(jobid,event,name,value) "
+ "values ('%|Ss',%d,'%|Ss','%|Ss')",
+ strlen(f[i].val) <= SHORT_LEN ? "short_fields" : "long_fields",
+ jobid,no,f[i].key,f[i].val);
+
+ if (edg_wll_ExecStmt(ctx,stmt,NULL) < 0) err = edg_wll_Error(ctx,NULL,NULL);
+ free(stmt);
+ }
+ for (i=0; i<sizeof(f)/sizeof(f[0]); i++) free(f[i].val);
+
+/* XXX: hardcoded, no other suitable place to store it */
+ trio_asprintf(&stmt,"insert into short_fields(jobid,event,name,value) "
+ "values ('%|Ss',%d,'SRC_INSTANCE','%|Ss')",
+ jobid,no,e->any.src_instance);
+ if (edg_wll_ExecStmt(ctx,stmt,NULL) < 0) err = edg_wll_Error(ctx,NULL,NULL);
+ free(stmt);
+
+ return err;
+}
+
+static int check_dup(edg_wll_Context ctx,edg_wll_Event *e)
+{
+ int i,dup_detected = 0;
+ int err;
+ char *es,*es2;
+ edg_wll_QueryRec jc[2],ec[2];
+ edg_wll_QueryRec **jca, **eca;
+ edg_wll_Event *e2;
+
+ edg_wll_ResetError(ctx);
+
+ jc[0].attr = EDG_WLL_QUERY_ATTR_JOBID;
+ jc[0].value.j = e->any.jobId;
+ jc[0].op = EDG_WLL_QUERY_OP_EQUAL;
+ jc[1].attr = EDG_WLL_QUERY_ATTR_UNDEF;
+
+ ec[0].attr = EDG_WLL_QUERY_ATTR_TIME;
+ memcpy(&ec[0].value.t,&e->any.timestamp,sizeof(struct timeval));
+ ec[0].op = EDG_WLL_QUERY_OP_EQUAL;
+ ec[1].attr = EDG_WLL_QUERY_ATTR_UNDEF;
+
+ jca = (edg_wll_QueryRec **) malloc (2 * sizeof(edg_wll_QueryRec **));
+ eca = (edg_wll_QueryRec **) malloc (2 * sizeof(edg_wll_QueryRec **));
+ jca[0] = jc;
+ jca[1] = NULL;
+ eca[0] = ec;
+ eca[1] = NULL;
+
+ err = edg_wll_QueryEventsServer(ctx,1,(const edg_wll_QueryRec **)jca,
+ (const edg_wll_QueryRec **)eca,&e2);
+ switch (err) {
+ case 0: /* continue normally */
+ break;
+ case ENOENT:
+ free(jca);
+ free(eca);
+ return edg_wll_ResetError(ctx);
+ break;
+ default:
+ free(jca);
+ free(eca);
+ return edg_wll_Error(ctx,NULL,NULL);
+ break;
+ }
+
+ es = edg_wll_UnparseEvent(ctx,e);
+ assert(es);
+
+ for (i=0;e2[i].type && !dup_detected;i++) {
+ /* Ignore priority */
+ e2[i].any.priority = e->any.priority;
+ es2 = edg_wll_UnparseEvent(ctx,e2+i);
+ assert(es2);
+ if (!strcmp(es,es2)) {
+ dup_detected = 1;
+ edg_wll_SetError(ctx,EEXIST,"duplicate event");
+ }
+ free(es2);
+ }
+
+ free(jca);
+ free(eca);
+ free(es);
+ for (i=0; e2[i].type; i++) edg_wll_FreeEvent(e2+i);
+ free(e2);
+ return edg_wll_Error(ctx,NULL,NULL);
+}
+
+static int check_auth(edg_wll_Context ctx,edg_wll_Event *e)
+{
+ char *jobid = edg_wlc_JobIdGetUnique(e->any.jobId);
+ char *q = NULL,*owner = NULL;
+ edg_wll_Stmt stmt = NULL;
+ char *user;
+
+ edg_wll_ResetError(ctx);
+
+ if (e->type == EDG_WLL_EVENT_REGJOB)
+ return strcmp(e->any.user,EDG_WLL_LOG_USER_DEFAULT) ?
+ 0 : edg_wll_SetError(ctx,EPERM,"can't register jobs anonymously");
+
+ trio_asprintf(&q,"select userid from jobs where jobid='%|Ss'",jobid);
+
+ if (edg_wll_ExecStmt(ctx,q,&stmt) < 0
+ || edg_wll_FetchRow(stmt,&owner) < 0
+ ) goto clean;
+
+ if (!owner) {
+ edg_wll_SetError(ctx,ENOENT,"job not registered");
+ goto clean;
+ }
+
+ switch (e->any.source) {
+ case EDG_WLL_SOURCE_USER_INTERFACE:
+ case EDG_WLL_SOURCE_LRMS:
+ case EDG_WLL_SOURCE_APPLICATION:
+ user = strmd5(e->any.user,NULL);
+ if (strcmp(owner,user)) edg_wll_SetError(ctx,EPERM,"check_auth()");
+ break;
+ default:
+ /* XXX: just don't allow anonymous */
+ if (!strcmp(e->any.user,EDG_WLL_LOG_USER_DEFAULT))
+ edg_wll_SetError(ctx,EPERM,"check_auth()");
+ break;
+ }
+
+
+clean:
+ if (stmt) edg_wll_FreeStmt(&stmt);
+ free(q);
+ free(owner);
+ return edg_wll_Error(ctx,NULL,NULL);
+}
+
+static int register_subjobs(edg_wll_Context ctx,const edg_wll_RegJobEvent *e)
+{
+ int i,err;
+ edg_wlc_JobId *subjobs;
+ struct timeval now;
+
+ edg_wll_ResetError(ctx);
+ if (e->nsubjobs == 0) return 0;
+ if (e->nsubjobs < 0) return edg_wll_SetError(ctx,EINVAL,"negative number of subjobs");
+
+ if ((err = edg_wll_GenerateSubjobIds(ctx,e->jobId,e->nsubjobs,e->seed,&subjobs)))
+ return err;
+
+ gettimeofday(&now,NULL);
+
+ for (i=0; i<e->nsubjobs; i++) {
+ edg_wll_Event e2;
+ int seq;
+ char *et,*ed,*job_s;
+
+ memset(&e2,0,sizeof e2);
+ e2.type = EDG_WLL_EVENT_REGJOB;
+ e2.any.jobId = subjobs[i]; subjobs[i] = NULL;
+ memcpy(&e2.regJob.timestamp,&now,sizeof now);
+ e2.any.host = strdup(ctx->srvName);
+ e2.any.level = e->level;
+ e2.any.priority = e->priority;
+ e2.any.seqcode = NULL; /* XXX: I'm not sure :-( */
+ e2.any.user = strdup(e->user);
+ e2.any.source = e->source;
+ e2.regJob.ns = strdup(e->ns);
+ edg_wlc_JobIdDup(e->jobId,&e2.regJob.parent);
+ e2.regJob.jobtype = EDG_WLL_REGJOB_SIMPLE;
+ e2.regJob.jdl = strdup("");
+
+ switch (edg_wll_StoreEvent(ctx,&e2,&seq)) {
+
+ case 0: break;
+ /* maybe some non-ignorable errors should be handled here */
+
+ default:
+ edg_wll_Error(ctx,&et,&ed);
+ job_s = edg_wlc_JobIdUnparse(e2.any.jobId);
+ fprintf(stderr,"register subjob %s: %s (%s)\n",job_s,et,ed);
+ syslog(LOG_ERR,"register subjob %s: %s (%s)",job_s,et,ed);
+ free(job_s); free(et); free(ed);
+ edg_wll_FreeEvent(&e2);
+ edg_wll_ResetError(ctx);
+ continue;
+ }
+
+ if (edg_wll_LockJob(ctx,e2.any.jobId)) {
+ job_s = edg_wlc_JobIdUnparse(e2.any.jobId);
+ fprintf(stderr,"lock job %s: %s (%s)\n",job_s,et,ed);
+ syslog(LOG_ERR,"lock job %s: %s (%s)",job_s,et,ed);
+ free(job_s); free(et); free(ed);
+ edg_wll_FreeEvent(&e2);
+ edg_wll_ResetError(ctx);
+ continue;
+ }
+
+ if ((err = edg_wll_StepIntState(ctx,e2.any.jobId,&e2,seq,NULL)))
+ edg_wll_Error(ctx,&et,&ed);
+
+ edg_wll_UnlockJob(ctx,e2.any.jobId);
+ edg_wll_ResetError(ctx);
+
+ if (err) {
+ job_s = edg_wlc_JobIdUnparse(e2.any.jobId);
+ fprintf(stderr,"%s: %s (%s)\n",job_s,et,ed);
+ syslog(LOG_ERR,"%s: %s (%s)",job_s,et,ed);
+ free(job_s); free(et); free(ed);
+ edg_wll_ResetError(ctx);
+ }
+
+ edg_wll_FreeEvent(&e2);
+ }
+
+ return edg_wll_Error(ctx,NULL,NULL);
+}
+
+int edg_wll_delete_event(edg_wll_Context ctx,const char *jobid,int event)
+{
+ char *stmt;
+
+/* The order of tables is important to prevent another process calling
+ * StoreEvent() to get our event number and mess up the fields together.
+ *
+ * XXX: best effort: more or less ignore errors
+ *
+ */
+
+ trio_asprintf(&stmt,
+ "delete from short_fields where jobid='%|Ss' and event=%d",
+ jobid,event);
+ edg_wll_ExecStmt(ctx,stmt,NULL);
+ free(stmt);
+
+ trio_asprintf(&stmt,
+ "delete from long_fields where jobid='%|Ss' and event=%d",
+ jobid,event);
+ edg_wll_ExecStmt(ctx,stmt,NULL);
+ free(stmt);
+
+ trio_asprintf(&stmt,
+ "delete from events where jobid='%|Ss' and event=%d",
+ jobid,event);
+ edg_wll_ExecStmt(ctx,stmt,NULL);
+ free (stmt);
+
+ return edg_wll_Error(ctx,NULL,NULL);
+}
--- /dev/null
+#ifndef _LBS_STORE_H
+#define _LBS_STORE_H
+
+#ident "$Header$"
+
+#include "glite/lb/consumer.h"
+#include "lb_authz.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* store an event into the LB database */
+
+int edg_wll_StoreEvent(
+ edg_wll_Context, /* INOUT */
+ edg_wll_Event *, /* IN */
+ int *
+);
+
+void edg_wll_StoreAnonymous(
+ edg_wll_Context, /* INOUT */
+ int /* IN (boolean) */
+);
+
+/* update stored job state according to new event */
+
+edg_wll_ErrorCode edg_wll_StepIntState(
+ edg_wll_Context, /* INOUT */
+ edg_wlc_JobId, /* IN */
+ edg_wll_Event *, /* IN */
+ int, /* IN */
+ edg_wll_JobStat *
+);
+
+int db_store(edg_wll_Context,char *,char *);
+int handle_request(edg_wll_Context,char *, int);
+int create_reply(const edg_wll_Context,char *,int);
+
+int edg_wll_delete_event(edg_wll_Context,const char *, int);
+
+
+#define USER_UNKNOWN "unknown"
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
--- /dev/null
+#ident "$Header$"
+
+#include <sys/time.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <string.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <assert.h>
+
+#include "glite/lb/il_string.h"
+#include "glite/lb/dgssl.h"
+#include "glite/lb/context-int.h"
+
+#include "store.h"
+
+int edg_wll_StoreProto(edg_wll_Context ctx)
+{
+ char fbuf[256],*buf;
+ int len,ret;
+ size_t total;
+
+ edg_wll_ResetError(ctx);
+ if ((ret=edg_wll_ssl_read_full(ctx->connPool[ctx->connToUse].ssl,fbuf,17,&ctx->p_tmp_timeout,&total)) < 0) switch (ret) {
+ case EDG_WLL_SSL_ERROR_TIMEOUT: return edg_wll_SetError(ctx,ETIMEDOUT,"read message header");
+ case EDG_WLL_SSL_ERROR_EOF: return edg_wll_SetError(ctx,ENOTCONN,NULL);
+ default: return edg_wll_SetError(ctx,EDG_WLL_ERROR_SSL,"read message header");
+ }
+
+ if ((len = atoi(fbuf)) <= 0) return edg_wll_SetError(ctx,EINVAL,"message length");
+
+ buf = malloc(len+1);
+
+ if ((ret=edg_wll_ssl_read_full(ctx->connPool[ctx->connToUse].ssl,buf,len,&ctx->p_tmp_timeout,&total)) < 0) {
+ free(buf);
+ return edg_wll_SetError(ctx,
+ ret == EDG_WLL_SSL_ERROR_TIMEOUT ?
+ ETIMEDOUT : EDG_WLL_ERROR_SSL,
+ "read message");
+ }
+
+
+ buf[len] = 0;
+
+ handle_request(ctx,buf,len);
+ free(buf);
+
+ if ((len = create_reply(ctx,fbuf,sizeof fbuf))) {
+ if ((ret = edg_wll_ssl_write_full(ctx->connPool[ctx->connToUse].ssl,fbuf,len,&ctx->p_tmp_timeout,&total)) < 0)
+ edg_wll_SetError(ctx,
+ ret == EDG_WLL_SSL_ERROR_TIMEOUT ?
+ ETIMEDOUT : EDG_WLL_ERROR_SSL,
+ "write reply");
+ }
+ else edg_wll_SetError(ctx,E2BIG,"create_reply()");
+
+ return edg_wll_Error(ctx,NULL,NULL);
+}
--- /dev/null
+#ident "$Header$"
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <errno.h>
+
+#include "glite/wms/jobid/cjobid.h"
+#include "glite/wms/jobid/strmd5.h"
+#include "glite/lb/context-int.h"
+#include "glite/lb/trio.h"
+
+#include "lbs_db.h"
+
+int edg_wll_UserJobs(
+ edg_wll_Context ctx,
+ edg_wlc_JobId **jobs,
+ edg_wll_JobStat **states)
+{
+ char *userid = strmd5(ctx->peerName,NULL),*stmt = NULL,
+ *res = NULL;
+ int njobs = 0,ret,i;
+ edg_wlc_JobId *out = NULL;
+ edg_wll_Stmt sth = NULL;
+ edg_wll_ErrorCode err = 0;
+
+ edg_wll_ResetError(ctx);
+
+ trio_asprintf(&stmt,"select cert_subj from users where userid = '%|Ss'",userid);
+
+ switch (edg_wll_ExecStmt(ctx,stmt,&sth)) {
+ case 0: edg_wll_SetError(ctx,ENOENT,ctx->peerName);
+ case -1: goto err;
+ default:
+ if (edg_wll_FetchRow(sth,&res) < 0) goto err;
+ if (strcmp(ctx->peerName,res)) {
+ edg_wll_SetError(ctx,EDG_WLL_ERROR_MD5_CLASH,ctx->peerName);
+ goto err;
+ }
+ }
+
+ edg_wll_FreeStmt(&sth);
+ free(stmt); stmt = NULL;
+ free(res); res = NULL;
+
+ trio_asprintf(&stmt,"select dg_jobid from jobs where userid = '%|Ss'",userid);
+ switch (njobs = edg_wll_ExecStmt(ctx,stmt,&sth)) {
+ case 0: edg_wll_SetError(ctx,ENOENT,ctx->peerName);
+ case -1: goto err;
+ }
+
+ out = malloc(sizeof(*out)*(njobs+1));
+ memset(out,0,sizeof(*out)*(njobs+1));
+
+ for (i=0; (ret = edg_wll_FetchRow(sth,&res)); i++) {
+ if (ret < 0) goto err;
+ if ((ret = edg_wlc_JobIdParse(res,out+i))) {
+ edg_wll_SetError(ctx,errno,res);
+ goto err;
+ }
+ free(res); res = NULL;
+ }
+
+err:
+ free(res);
+ free(stmt);
+ edg_wll_FreeStmt(&sth);
+ if ((err = edg_wll_Error(ctx,NULL,NULL))) {
+ if (out) {
+ for (i=0; i<njobs; i++)
+ edg_wlc_JobIdFree(out[i]);
+ free(out);
+ }
+ } else *jobs = out;
+
+ return err;
+}
--- /dev/null
+#ident "$Header$"
+
+#include <assert.h>
+#include <fcntl.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/file.h>
+#include <sys/socket.h>
+#include <sys/types.h>
+#include <sys/un.h>
+#include <sys/uio.h>
+
+
+#include "glite/lb/trio.h"
+#include "glite/lb/producer.h"
+#include "glite/lb/context-int.h"
+#include "glite/lb/jobstat.h"
+
+#include "get_events.h"
+#include "store.h"
+#include "lock.h"
+#include "index.h"
+#include "jobstat.h"
+
+static int rgma_fd = -1;
+static int rgma_sock = -1;
+static struct sockaddr_un rgma_saddr;
+
+static void write2rgma_sql(char *sqlstat)
+{
+
+ char *rgma_fname;
+ int slen;
+ int sysret;
+ struct iovec iov[2];
+
+ assert(sqlstat != NULL);
+
+ if (rgma_fd == -1) {
+ rgma_fname = getenv("EDG_WL_RGMA_FILE");
+ if (rgma_fname == NULL) return;
+
+ rgma_fd = open(rgma_fname, O_WRONLY|O_CREAT|O_APPEND, 0777);
+ if (rgma_fd == -1) return;
+ }
+
+ slen = strlen(sqlstat);
+ iov[0].iov_base = &slen;
+ iov[0].iov_len = sizeof(slen);
+ iov[1].iov_base = sqlstat;
+ iov[1].iov_len = slen + 1;
+ if ((sysret = flock(rgma_fd, LOCK_SH)) != -1) {
+ sysret = writev(rgma_fd, iov, 2);
+ flock(rgma_fd, LOCK_UN);
+ }
+
+ if (sysret == -1) return;
+
+ if (rgma_sock == -1) {
+ rgma_fname = getenv("EDG_WL_RGMA_SOCK");
+ if (rgma_fname == NULL) return;
+
+ if ((strlen(rgma_fname) + 1) > sizeof(rgma_saddr.sun_path))
+ return ;
+
+ rgma_sock = socket(PF_UNIX, SOCK_DGRAM,0);
+ if (rgma_sock == -1) return;
+
+ memset(&rgma_saddr, sizeof(rgma_saddr), 0);
+ rgma_saddr.sun_family = PF_UNIX;
+ strcpy(rgma_saddr.sun_path, rgma_fname);
+ }
+
+ sendto(rgma_sock, &slen, 1, 0,
+ (struct sockaddr*) &rgma_saddr, SUN_LEN(&rgma_saddr));
+
+ return;
+}
+
+void write2rgma_status(edg_wll_JobStat *stat)
+{
+ char *stmt = NULL;
+ char *string_jobid, *string_stat, *string_server;
+
+ string_jobid = edg_wlc_JobIdUnparse(stat->jobId);
+ string_stat = edg_wll_StatToString(stat->state);
+ string_server = edg_wlc_JobIdGetServer(stat->jobId);
+
+ trio_asprintf(&stmt, "INSERT INTO JobStatusRaw VALUES ('%|Ss','%s','%|Ss','%|Ss', '%d%03d')",
+ string_jobid, string_stat, stat->owner, string_server,
+ stat->stateEnterTime.tv_sec, stat->stateEnterTime.tv_usec/1000);
+
+ if (stmt) write2rgma_sql(stmt);
+
+ free(string_jobid);
+ free(string_stat);
+ free(string_server);
+ free(stmt);
+}
+
+#ifdef TEST
+int main(int argc, char* argv[])
+{
+ setenv("EDG_WL_RGMA_FILE", "/tmp/rgma_statefile", 1);
+ setenv("EDG_WL_RGMA_SOCK", "/tmp/rgma_statesock", 1);
+
+ write2rgma_sql("INSERT INTO JobStatusRaw VALUES ('Job_id9','CLEARED','Owner','BKServer', '1050024158210')");
+ return 0;
+}
+#endif
--- /dev/null
+<?xml version="1.0" encoding="UTF-8" ?>
+
+<project name="lb" default="dist">
+
+ <import file="../org.glite/project/baseline.properties.xml" />
+ <import file="./project/properties.xml"/>
+ <import file="${subsystem.properties.file}"/>
+ <import file="${global.properties.file}" />
+
+ <property file="${user.dependencies.file}"/>
+ <property file="${component.dependencies.file}" />
+ <property file="${subsystem.dependencies.file}" />
+ <property file="${global.dependencies.file}"/>
+
+ <import file="${subsystem.taskdefs.file}" />
+ <import file="${global.taskdefs.file}" />
+
+ <import file="${global.targets-external-dependencies.file}"/>
+ <import file="${global.targets-make.file}" />
+
+ <property file="${module.version.file}"/>
+
+ <target name="localinit"
+ description="Module specific initialization tasks">
+ </target>
+
+ <target name="localcompile"
+ description="Module specific compile tasks">
+ </target>
+
+ <target name="localclean"
+ description="Module specific cleaning tasks">
+ </target>
+
+</project>
--- /dev/null
+package MultiStruct;
+
+use StructField;
+
+sub new {
+ shift;
+ my $self = {};
+ $self->{comments} = {}; # typ->comment
+ $self->{fields} = {}; # typ->{ name->StructField, ... }
+ $self->{order} = {};
+
+ bless $self;
+}
+
+sub selectType {
+ my $self = shift;
+ my $type = shift;
+ $self->{type} = $type;
+ 1;
+}
+
+sub addType {
+ my $self = shift;
+ my $type = shift;
+ my $comment = shift;
+ $self->selectType($type);
+ $self->{comments}->{$type} = $comment;
+ $self->{fields}->{$type} = {};
+ 1;
+}
+
+sub selectField {
+ my $self = shift;
+ $self->{field} = shift;
+ $self->getField;
+}
+
+sub addField {
+ my $self = shift;
+ my $field = shift;
+
+ die "unselected type" unless $self->{type};
+ $self->{fields}->{$self->{type}}->{$field->{name}} = $field;
+ $self->selectField($field->{name});
+ 1;
+}
+
+sub getField {
+ my $self = shift;
+ my $f = $self->{fields}->{$self->{type}}->{$self->{field}};
+ return $f ? $f : $self->{fields}->{_common_}->{$self->{field}};
+}
+
+sub load {
+ my $self = shift;
+ my $fh = shift;
+ local $_;
+
+ while ($_ = <$fh>) {
+
+ chomp;
+ s/#.*$//;
+ next if /^\s*$/;
+
+ if (/^\@type\s+(\S+)\s*(.*$)$/) {
+ $self->addType($1,$2);
+ $self->{order}->{$1} = $.;
+ next;
+ }
+
+ s/^\s*//;
+ my ($ftype,$fname,$comment) = split /\s+/,$_,3;
+ if ($ftype eq '_code_') {
+ my $f = $self->getField();
+ addCode $f $fname,$comment;
+ }
+ elsif ($ftype eq '_alias_') {
+ my $f = $self->getField();
+ addAlias $f $fname,$comment;
+ }
+ elsif ($ftype eq '_special_') {
+ my $f = $self->getField();
+ addSpecial $f $fname;
+ }
+ elsif ($ftype eq '_null_') {
+ my $f = $self->getField();
+ setNull $f $fname;
+ }
+ elsif ($ftype eq '_optional_') {
+ my $f = $self->getField();
+ $f->{optional} = 1;
+ }
+ elsif ($ftype eq '_index_') {
+ my $f = $self->getField();
+ $f->{index} = 1;
+ }
+ else {
+ my $f = new StructField $fname,$ftype,$comment,$.;
+ $self->addField($f);
+ }
+ }
+}
+
+sub getTypes {
+ my $self = shift;
+ my @out;
+ local $_;
+
+ for (keys %{$self->{fields}}) {
+ push @out,$_ unless $_ eq '_common_';
+ }
+ @out;
+}
+
+sub getTypesOrdered {
+ my $self = shift;
+ my @names = getTypes $self;
+
+ sort {
+ my $oa = $self->{order}->{$a};
+ my $ob = $self->{order}->{$b};
+ $oa <=> $ob;
+ } @names;
+}
+
+sub getTypeComment {
+ my $self = shift;
+ my $type = shift || $self->{type};
+ $self->{comments}->{$type};
+}
+
+sub getFieldComment {
+ my $self = shift;
+ my $fname = shift;
+ $self->{fields}->{$self->{type}}->{$fname}->{comment};
+}
+
+sub getFields {
+ my $self = shift;
+ keys %{$self->{fields}->{$self->{type}}};
+}
+
+sub getFieldsOrdered {
+ my $self = shift;
+ my @names = $self->getFields;
+ sort {
+ my $oa = $self->selectField($a)->{order};
+ my $ob = $self->selectField($b)->{order};
+ $oa <=> $ob;
+ } @names;
+}
+
+sub getFieldOccurence {
+ my $self = shift;
+ my $fname = shift;
+ my @out;
+ local $_;
+
+ for (keys %{$self->{fields}}) {
+ push @out,$_ if $self->{fields}->{$_}->{$fname};
+ }
+ @out;
+}
+
+sub getAllFields {
+ my $self = shift;
+ my %out;
+ local $_;
+
+ for my $t (values %{$self->{fields}}) {
+ $out{$_->{name}} = 1 for (values %$t);
+ }
+ keys %out;
+}
+
+sub getAllFieldsOrdered {
+ my $self = shift;
+ my @names = getAllFields $self;
+
+ sort {
+ my @occ = $self->getFieldOccurence($a);
+ $self->selectType($occ[0]);
+ my $oa = $self->selectField($a)->{order};
+ @occ = $self->getFieldOccurence($b);
+ $self->selectType($occ[0]);
+ my $ob = $self->selectField($b)->{order};
+ $oa <=> $ob;
+ } @names;
+}
+
+1;
--- /dev/null
+package StructField;
+
+$lang = 'C';
+1;
+
+sub new {
+ shift;
+ my $self = {};
+ $self->{name} = shift;
+ $self->{type} = shift;
+ $self->{comment} = shift;
+ $self->{order} = shift;
+ $self->{null} = $main::DefaultNullValue{$self->{type}};
+ bless $self;
+}
+
+sub addCode {
+ my $self = shift;
+ my $code = shift;
+ my $comment = shift;
+ push @{$self->{codes}},{name=>$code,comment=>$comment};
+ 1;
+}
+
+sub addSpecial {
+ my $self = shift;
+ my $special = shift;
+ $self->{special} = $special;
+ 1;
+}
+
+sub addAlias {
+ my $self = shift;
+ my $name = shift;
+ my $lang = shift;
+ $self->{aliases}->{$lang} = $name;
+ 1;
+}
+
+sub hasAlias {
+ my $self = shift;
+ my $lang = shift;
+ return $self->{aliases}->{$lang} ? 1 : 0;
+}
+
+sub getName {
+ my $self = shift;
+ my $lang = shift || $lang;
+ $self->{aliases}->{$lang} || $self->{name};
+# return $self->{aliases}->{$lang} ? $self->{aliases}->{$lang} : $self->{name};
+}
+
+sub getComment {
+ my $self = shift;
+ $self->{comment};
+}
+
+sub getDefaultNullValue {
+ my $self = shift;
+ $self->{null};
+}
+
+sub toString {
+ my $self = shift;
+ my $src = shift;
+ my $dst = shift;
+
+ eval $main::toString{$lang}->{$self->{type}};
+}
+
+sub fromString {
+ my $self = shift;
+ my $src = shift;
+ my $dst = shift;
+
+ eval $main::fromString{$lang}->{$self->{type}};
+}
+
+sub isNULL {
+ my $self = shift;
+ my $a = shift;
+ my $b = $self->{null};
+
+ eval $main::compare{$lang}->{$self->{type}};
+}
+
+sub isnotNULL {
+ my $self = shift;
+ my $src = shift;
+
+ '!('.$self->isNULL($src).')';
+}
+
+sub compare {
+ my $self = shift;
+ my $a = shift;
+ my $b = shift;
+ eval $main::compare{$lang}->{$self->{type}};
+}
+
+sub toFormatString {
+ my $self = shift;
+
+ eval $main::toFormatString{$lang}->{$self->{type}};
+}
+
+sub setNull {
+ my $self = shift;
+ $self->{null} = shift;
+}
+
+sub getType {
+ my $self = shift;
+
+ eval $main::types{$lang}->{$self->{type}};
+}
--- /dev/null
+#!/usr/bin/perl -w
+
+use File::Basename;
+my $dir;
+BEGIN{
+ $dir = dirname $0;
+}
+
+my $lines = $ENV{AT3_LINES};
+
+use lib $dir;
+use MultiStruct;
+require 'types.T';
+
+my $eventsn;
+for (@INC) {
+ if (-f "$_/events.T") {
+ $eventsn="$_/events.T";
+ last;
+ }
+}
+
+my $statusn;
+for (@INC) {
+ if (-f "$_/status.T") {
+ $statusn = "$_/status.T";
+ last;
+ }
+}
+
+my $indent = '';
+
+my $event = new MultiStruct;
+my $status = new MultiStruct;
+
+sub gen {
+ local $_ = shift;
+
+ s/^\n!//;
+ s/\n!/\n/g;
+ print $_;
+}
+
+
+open EVENTS,$eventsn or die "$eventsn: $!\n";
+$event->load(\*EVENTS);
+close EVENTS;
+
+open STATUS,$statusn or die "$statusn: $!\n";
+$status->load(\*STATUS);
+close STATUS;
+
+my $code;
+my $startcode;
+while (<>) {
+ chomp;
+ if (/^\@\@\@LANG: (\S+)$/) {
+ $StructField::lang = $1;
+ next;
+ }
+
+ if ($code) {
+ if (/^\@\@\@}$/) {
+ $code .= "1;\n";
+ print "#line $startcode \"$ARGV\"\n/* begin */\n" if $lines;
+ eval $code or warn "eval: $@ at $ARGV:$.\n";
+ my $nxtline = $.+1;
+ print "/* end */\n#line $nxtline \"$ARGV\"\n" if $lines;
+ undef $code;
+ }
+ else { $code .= $_."\n"; }
+ }
+ else {
+ if (/^\@\@\@{$/) {
+ $startcode = $.;
+ $code = "\n";
+ }
+ elsif (/^\@\@\@AUTO$/) {
+ print qq{
+ !! Automatically generated file
+ !! Do not edit, your changes will be discarded upon build
+ !! Change the corresponding template file $ARGV
+
+};
+ print "#line $. \"$ARGV\"\n" if $lines;
+ }
+ else {
+ print "$_\n";
+ }
+ }
+}
+
+# print $event_common{prog}->copy('bla','hu');
--- /dev/null
+org.glite.version = HEAD
+org.glite.wms.thirdparty-globus_ssl_utils.version = HEAD
+org.glite.wms.jobid.version = HEAD
--- /dev/null
+@type _common_
+ timeval timestamp timestamp of event generation
+ _alias_ date ULM
+ timeval arrived timestamp of event store
+ _alias_ arr_date ULM
+ _optional_
+ string host hostname of the machine where the event was generated
+ _alias_ host ULM
+ int level logging level (system, debug, ...)
+ _alias_ lvl ULM
+ _code_ EMERGENCY emergency
+ _code_ ALERT alert
+ _code_ ERROR error
+ _code_ WARNING warning
+ _code_ AUTH authentication
+ _code_ SECURITY security
+ _code_ USAGE usage
+ _code_ SYSTEM system
+ _code_ IMPORTANT important
+ _code_ DEBUG debug
+ int priority message priority (yet 0 for asynchronous and 1 for synchronous transfers)
+ _null_ -1
+ jobid jobId DataGrid job id of the source job
+ string seqcode sequence code assigned to the event
+ string user identity (cert. subj.) of the generator
+ logsrc source source (WMS component) which generated this event
+# string prog name of program ("EDG WMS" of name of the application)
+ string src_instance instance of WMS component (e.g. service communication endpoint)
+ _optional_
+
+@type Transfer Start, success, or failure of job transfer to another component
+ logsrc destination destination where the job is being transfered to
+ string dest_host destination hostname
+ string dest_instance destination instance
+ _optional_
+ string job job description in receiver language
+ int result result of the attempt
+ _code_ START the sending component has started or is about to start the transfer
+ _code_ OK job was sent successfully
+ _code_ REFUSED job was refused by the other component
+ _code_ FAIL transfer failed for other reason than explicit refusal (eg. network timeout)
+ string reason detailed description of transfer, especially reason of failure
+ _optional_
+ string dest_jobid destination internal jobid
+ _optional_
+
+@type Accepted Accepting job (successful couterpart to Transfer)
+ logsrc from where was the job received from
+ string from_host sending component hostname
+ string from_instance sending component instance
+ _optional_
+ string local_jobid new jobId (Condor, Globus ...) assigned by the receiving component
+
+@type Refused Refusing job (unsuccessful couterpart to Transfer)
+ logsrc from where was the job received from
+ string from_host sending component hostname
+ string from_instance sending component instance
+ _optional_
+ string reason reason of refusal
+
+@type EnQueued The job has been enqueued in an inter-component queue
+ string queue destination queue
+ string job job description in receiver language
+ int result result of the attempt
+ _code_ START the sending component has started or is about to start the transfer
+ _code_ OK job was sent successfully
+ _code_ REFUSED job was refused by the other component
+ _code_ FAIL transfer failed for other reason than explicit refusal (eg. network timeout)
+ string reason detailed description of transfer, especially reason of failure
+
+@type DeQueued The job has been dequeued from an inter-component queue
+ string queue queue name
+ string local_jobid new jobId assigned by the receiving component
+
+@type HelperCall Helper component is called
+ string helper_name name of the called component
+ string helper_params parameters of the call
+ int src_role whether the logging component is called or calling one
+ _code_ CALLING the logging component is caller
+ _code_ CALLED the logging component is callee
+
+@type HelperReturn Helper component is returning the control
+ string helper_name name of the called component
+ string retval returned data
+ int src_role whether the logging component is called or calling one
+ _code_ CALLING the logging component is caller
+ _code_ CALLED the logging component is callee
+
+@type Running Executable started
+ string node worker node where the executable is run
+
+@type Resubmission Result of resubmission decision
+ int result result code
+ _code_ WILLRESUB will be resubmitted
+ _code_ WONTRESUB will not be resubmitted
+ string reason reason for the decision
+ string tag value of the attribute on which the decision is based
+
+@type Done Execution terminated (normally or abnormally)
+ int status_code way of termination
+ _code_ OK terminated by itself
+ _code_ FAILED disappeared from LRMS
+ _code_ CANCELLED cancelled by user request
+ string reason reason for the change
+ int exit_code process exit code
+ _null_ -1
+
+@type Cancel Cancel operation has been attempted on the job
+ int status_code classification of the cancel
+ _code_ REQ request acknowledged
+ _code_ REFUSE request declined by this component
+ _code_ DONE request completed by whole WMS
+ _code_ ABORT request refused by whole WMS
+ string reason detailed description
+
+@type Abort Job aborted by system
+ string reason reason of abort
+
+@type Clear Job cleared, output sandbox removed
+ int reason why the job was cleared
+ _code_ USER user retrieved output sandbox
+ _code_ TIMEOUT timed out, resource purge forced
+ _code_ NOOUTPUT no output was generated
+
+@type Purge Job is purged from bookkepping server
+
+@type Match Matching CE found
+ string dest_id Id of the destination CE/queue
+
+@type Pending No match found yet
+ string reason why matching CE cannot be found
+
+@type RegJob New job registration
+ string jdl job description
+ string ns NetworkServer handling the job
+ jobid parent jobid of parent job
+ _optional_
+
+ int jobtype job type
+ _code_ SIMPLE simple job
+ _code_ DAG dag (containing static set of subjobs)
+ _code_ PARTITIONABLE partitionable (may become partitioned)
+ _code_ PARTITIONED partitioned (dynamically created dag)
+
+ int nsubjobs number of subjobs
+ _optional_
+ string seed seed for subjob id generation
+ _optional_
+
+@type Chkpt Application-specific checkpoint record
+ string tag checkpoint tag
+ string classad checkpoint value
+
+@type Listener Listening network port for interactive control
+ string svc_name port instance name
+ string svc_host hostname
+ port svc_port port number
+
+@type CurDescr current state of job processing (optional event)
+ string descr description of current job transformation (output of helper)
+
+@type UserTag user tag -- arbitrary name=value pair
+ string name tag name
+ string value tag value
+
+@type ChangeACL Management of ACL stored on bookkepping server
+ string user_id DN or VOMS parameter (in format VO:group)
+ int user_id_type type of information given in user_id (DN or VOMS)
+ _null_ -1
+ int permission ACL permission to change (currently only READ)
+ _null_ -1
+ int permission_type type of permission requested ('allow', 'deny')
+ _null_ -1
+ int operation operation requested to perform with ACL (add, remove)
+ _null_ -1
+
+@type Notification Management of notification service
+ notifid notifId notification id
+ string owner owner
+ string dest_host destination host
+ port dest_port destination port
+ string jobstat job status
+
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+
+<project name="LB Subsystem common properties">
+ <property name="subsystem.build.properties.file" value="./project/build.properties" />
+ <property file="${subsystem.build.properties.file}" />
+ <property name="subsystem.name" value="${lb.subsystem.name}"/>
+ <property name="subsystem.prefix" value="${lb.subsystem.prefix}"/>
+
+ <import file="${subsystem.general.properties.file}" />
+
+ <!-- XXX: should be resolved at project level -->
+ <property name="ext.ares.subdir" value="ares" />
+ <property name="ext.expat.subdir" value="expat" />
+ <property name="ext.voms.subdir" value="voms" />
+ <property name="ext.gacl.subdir" value="gacl" />
+ <property name="ext.mysql.subdir" value="mysql" />
+</project>
--- /dev/null
+@type _common_
+jobid jobId Id of the job
+string owner Job owner
+_index_
+
+int jobtype Type of job
+ _null_ -1
+ _code_ SIMPLE simple job
+ _code_ DAG composite job
+jobid parent_job parent job of subjob
+
+string seed string used for generation of subjob IDs
+int children_num number of subjobs
+strlist children list of subjob IDs
+ _special_ XMLstructured
+intlist children_hist summary (histogram) of children job states
+ _special_ XMLstructured
+stslist children_states full status information of the children
+ _special_ XMLstructured
+
+string condorId Id within Condor-G
+string globusId Globus allocated Id
+string localId Id within LRMS
+
+string jdl User submitted job description
+string matched_jdl Full job description after matchmaking
+string destination ID of CE where the job is being sent
+_index_
+string condor_jdl ClassAd passed to Condor-G for last job execution
+string rsl Job RSL sent to Globus
+
+string reason Reason of being in this status, if any
+
+string location Where the job is being processed
+_index_
+string ce_node Worker node where the job is executed
+string network_server Network server handling the job
+
+bool subjob_failed Subjob failed (the parent job will fail too)
+int done_code Return code
+ _null_ -1
+ _code_ OK Finished correctly
+ _code_ FAILED Execution failed
+ _code_ CANCELLED Cancelled by user
+int exit_code Unix exit code
+bool resubmitted The job was resubmitted
+
+bool cancelling Cancellation request in progress
+string cancelReason Reason of cancel
+
+int cpuTime Consumed CPU time
+ _null_ -1
+
+taglist user_tags List of pairs (user_tag, user_value)
+ _special_ XMLstructured
+
+timeval stateEnterTime When entered this status
+timeval lastUpdateTime Last known event of the job
+
+intlist stateEnterTimes When all previous states were entered
+ _special_ XMLstructured
+
+bool expectUpdate Some logged information has not arrived yet
+string expectFrom Sources of the missing information
+string acl ACL of the job
+
+@type Submitted entered by the user to the User Interface or registered by Job Partitioner
+@type Waiting Accepted by WMS, waiting for resource allocation
+@type Ready Matching resources found
+@type Scheduled Accepted by LRMS queue
+@type Running Executable is running
+@type Done Execution finished, output is available
+@type Cleared Output transfered back to user and freed
+@type Aborted Aborted by system (at any stage)
+@type Cancelled Cancelled by user
+@type Unknown Status cannot be determined
+@type Purged Job has been purged from bookkeeping server (for LB->RGMA interface)
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+
+<project name="LB Subsystem common tasks and types definitions">
+ <target name="lbmakefiles">
+ <exec executable="ln" failonerror="true">
+ <arg line="-fs ${component.dir}/Makefile ${module.build.dir}/Makefile"/>
+ </exec>
+ <echo file="${module.build.dir}/Makefile.inc">
+repository=${repository}
+platform=${platform}
+globus=${ext.globus.subdir}
+lbproject=${subsystem.project.dir}
+lbconfig=${subsystem.dir}/config
+src=${module.src.dir}
+interface=${module.int.dir}
+autosrc=${module.autosrc.dir}
+stageinc=${stage.inc.dir}
+stagelib=${stage.lib.dir}
+stagebin=${stage.bin.dir}
+globalprefix=${global.prefix}
+lbprefix=${subsystem.prefix}
+installdir=${install.dir}
+globusflavour=gcc32dbg
+ares=${ext.ares.subdir}
+expat=${ext.expat.subdir}
+voms=${ext.voms.subdir}
+gacl=${ext.gacl.subdir}
+mysql=${ext.mysql.subdir}
+</echo>
+ </target>
+
+ <target name="clean-autotools">
+ </target>
+</project>
--- /dev/null
+%types = (
+ C=>{
+ bool=>'"int"',
+ string=>'"char *"',
+ strlist=>'"char **"',
+ intlist=>'"int *"',
+ taglist=>'"edg_wll_TagValue *"',
+ stslist=>'"struct _edg_wll_JobStat *"',
+ timeval=>'"struct timeval"',
+ jobid=>'"edg_wlc_JobId"',
+ notifid=>'"edg_wll_NotifId"',
+ logsrc=>'"edg_wll_Source"',
+ port=>'"uint16_t"',
+# level=>'"enum edg_wll_Level"',
+ int=>'"int"'
+ },
+ 'C++'=>{
+ string=>'"std::string"',
+ timeval=>'"struct timeval"',
+ jobid=>'"edg::workload::common::jobid::JobId"',
+ bool=>'"int"',
+ intlist=>'"std::vector<int>"',
+ strlist=>'"std::vector<std::string>"',
+ taglist=>'"std::vector<std::pair<std::string>>"',
+ stslist=>'"std::vector<JobStatus>"',
+ logsrc=>'"int"',
+ port=>'"int"',
+ int=>'"int"'
+ }
+);
+
+%toString = (
+ C=>{
+ int=>'qq{asprintf(&$dst,"%d",$src);}',
+ port=>'qq{asprintf(&$dst,"%d",(int) $src);}',
+ bool=>'qq{asprintf(&$dst,"%d",$src);}',
+ string=>'qq{$dst = $src?strdup($src):NULL;}',
+ timeval=>'qq{edg_wll_ULMTimevalToDate(($src).tv_sec,($src).tv_usec,$dst);}',
+ jobid=>'qq{$dst = edg_wlc_JobIdUnparse($src);}',
+ notifid=>'qq{$dst = edg_wll_NotifIdUnparse($src);}',
+# level=>'qq{$dst = edg_wll_LevelToString($src);}',
+ logsrc=>'qq{$dst = edg_wll_SourceToString($src);}',
+# strlist, intlist, stslist are used only in consumer API, they don't need toString method
+ }
+);
+
+%ULMasString = (
+ logsrc=>1
+);
+
+%fromString = (
+ C=>{
+ int=>'qq{$dst = atoi($src);}',
+ port=>'qq{$dst = (uint16_t) atoi($src);}',
+ bool=>'qq{$dst = atoi($src);}',
+ string=>'qq{$dst = strdup($src);}',
+ timeval=>'qq{edg_wll_ULMDateToTimeval($src,&$dst);}',
+ jobid=>'qq{edg_wlc_JobIdParse($src,&$dst);}',
+ notifid=>'qq{edg_wll_NotifIdParse($src,&$dst);}',
+# level=>'qq{$dst = edg_wll_StringToLevel($src);}',
+ logsrc=>'qq{$dst = edg_wll_StringToSource($src);}',
+# strlist, intlist, stslist are used only in consumer API, they don't need fromString method
+ }
+);
+
+%DefaultNullValue = (
+ int=>0,
+ port=>0,
+# level=>'EDG_WLL_LEVEL_UNDEFINED',
+ bool=>0,
+ string=>'NULL',
+ jobid=>'NULL',
+ notifid=>'NULL',
+ logsrc=>'EDG_WLL_SOURCE_NONE',
+ timeval=>'null_timeval',
+ strlist=>'NULL',
+ intlist=>'NULL',
+ taglist=>'NULL',
+ stslist=>'NULL',
+);
+
+%compare = (
+ C=>{
+ int=>'"($a == $b)"',
+ port=>'"($a == $b)"',
+# level=>'"($a == $b)"',
+ bool=>'"(($a || !$b) && ($b || !$a))"',
+ string=>'"(($a) == NULL && ($b) == NULL) || (($a)&&($b)&& !strcmp($a,$b))"',
+ jobid=>'"($a) == ($b)"',
+ notifid=>'"($a) == ($b)"',
+ logsrc=>'"($a) == ($b)"',
+ timeval=>'"($a).tv_sec == ($b).tv_sec && ($a).tv_usec == ($b).tv_usec"',
+ }
+);
+
+%toFormatString = (
+ C=>{
+ int=>'"%d"',
+ port=>'"%d"',
+ bool=>'"%d"',
+# level=>'"%s"',
+ string=>'"%|Us"',
+ jobid=>'"%s"',
+ notifid=>'"%s"',
+ logsrc=>'"%s"',
+ timeval=>'"%s"',
+ }
+);