/** Create a BufferedWriter instance * * \param outStream opaque OmlOutStream handler * \param queueCapacity maximal size [B] of the internal queue queueCapaity/chunkSize will be used (at least 2) * \param chunkSize size [B] of buffer space allocated at a time, set to 0 for default (DEF_CHAIN_BUFFER_SIZE) * \return an instance pointer if successful, NULL otherwise * * \see DEF_CHAIN_BUFFER_SIZE */ BufferedWriter* bw_create(OmlOutStream* outStream, long queueCapacity, long chunkSize) { long nchunks; BufferedWriter* self = NULL; assert(outStream>=0); assert(queueCapacity>=0); assert(chunkSize>=0); if((self = (BufferedWriter*)oml_malloc(sizeof(BufferedWriter)))) { memset(self, 0, sizeof(BufferedWriter)); self->outStream = outStream; /* This forces a 'connected' INFO message upon first connection */ self->backoff = 1; self->bufSize = chunkSize > 0 ? chunkSize : DEF_CHAIN_BUFFER_SIZE; nchunks = queueCapacity / self->bufSize; self->unallocatedBuffers = (nchunks > 2) ? nchunks : 2; /* at least two chunks */ logdebug ("%s: Buffer size %dB (%d chunks of %dB)\n", self->outStream->dest, self->unallocatedBuffers*self->bufSize, self->unallocatedBuffers, self->bufSize); if(NULL == (self->writerChunk = self->nextReaderChunk = self->firstChunk = createBufferChunk(self))) { oml_free(self); self = NULL; } else if(NULL == (self->meta_buf = mbuf_create())) { destroyBufferChain(self); oml_free(self); self = NULL; } else if(NULL == (self->read_buf = mbuf_create())) { destroyBufferChain(self); oml_free(self); self = NULL; } else { /* Initialize mutex and condition variable objects */ pthread_cond_init(&self->semaphore, NULL); pthread_mutex_init(&self->lock, NULL); logdebug3("%s: initialised mutex %p\n", self->outStream->dest, &self->lock); pthread_mutex_init(&self->meta_lock, NULL); logdebug3("%s: initialised mutex %p\n", self->outStream->dest, &self->meta_lock); /* Initialize and set thread detached attribute */ pthread_attr_t tattr; pthread_attr_init(&tattr); pthread_attr_setdetachstate(&tattr, PTHREAD_CREATE_JOINABLE); self->active = 1; pthread_create(&self->readerThread, &tattr, bufferedWriterThread, (void*)self); } } return (BufferedWriter*)self; }
void client_free (Client *client) { if (client == NULL) return; if (client->file) { fflush (client->file); fclose (client->file); client->file = NULL; } oml_free (client->file_name); oml_free (client->downstream_addr); struct header *header = client->headers; while (header) { struct header *next = header->next; header_free (header); header = next; } msg_queue_destroy (client->messages); cbuf_destroy (client->cbuf); pthread_cond_destroy (&client->condvar); pthread_mutex_destroy (&client->mutex); socket_free (client->recv_socket); oml_free (client); }
/** Terminate the Socket and free its allocated memory. * * If the socket is still open, it will be closed. * * \param socket Socket to free * \see socket_new, socket_close */ void socket_free (Socket* socket) { SocketInt* self = (SocketInt *)socket; socket_close(socket); if (self->name) { oml_free(self->name); } if (self->dest) { oml_free(self->dest); } if (self->service) { oml_free(self->service); } if (self->results) { freeaddrinfo(self->results); } oml_free (self); }
/** Deallocate a TableDescr array * * \param tables beginning of the array * \param n size of the array */ void table_descr_array_free (TableDescr* tables, int n) { int i = 0; for (i = 0; i < n; i++) { oml_free (tables[i].name); if (tables[i].schema) { schema_free (tables[i].schema); } } oml_free(tables); }
/** Find a database instance for name. * * If no database with this name exists, a new one is created. * * \param name name of the database to find * \return a pointer to the database */ Database* database_find (const char* name) { Database* db = first_db; while (db != NULL) { if (!strcmp(name, db->name)) { loginfo ("%s: Database already open (%d client%s)\n", name, db->ref_count, db->ref_count>1?"s":""); db->ref_count++; return db; } db = db->next; } // need to create a new one Database *self = oml_malloc(sizeof(Database)); logdebug("%s: Creating or opening database\n", name); strncpy(self->name, name, MAX_DB_NAME_SIZE); self->ref_count = 1; self->create = database_create_function (dbbackend); if (self->create (self)) { oml_free(self); return NULL; } if (database_init (self) == -1) { database_release(self); oml_free (self); return NULL; } char *start_time_str = self->get_metadata (self, "start_time"); if (start_time_str == NULL) { /* No start time: this is probably a new database */ database_hook_send_event(self, HOOK_CMD_DBCREATED); } else { database_hook_send_event(self, HOOK_CMD_DBOPENED); self->start_time = strtol (start_time_str, NULL, 0); oml_free (start_time_str); logdebug("%s: Retrieved start-time = %lu\n", name, self->start_time); } // hook this one into the list of active databases self->next = first_db; first_db = self; return self; }
/** Unregister all built-in filters. */ void unregister_filters () { FilterType* ft = filter_types; logdebug("Unregistering filters\n"); while(ft) { filter_types = ft->next; oml_free(ft->definition); oml_free(ft); ft = filter_types; }; }
/** Deallocate a TableDescr linked list * * Also free the encapsulated schema structures. * * \param tables head of the list */ void table_descr_list_free (TableDescr* tables) { TableDescr* t = tables; while (t) { TableDescr* next = t->next; oml_free (t->name); if (t->schema) { schema_free (t->schema); } oml_free (t); t = next; } }
/** Destroy the Buffer chain of a BufferedWriter * * \param self pointer to the BufferedWriter * * \return 0 on success, or a negative number otherwise */ int destroyBufferChain(BufferedWriter* self) { BufferChunk *chunk, *start; if (!self) { return -1; } /* BufferChunk is a circular buffer */ start = self->firstChunk; while( (chunk = self->firstChunk) && chunk!=start) { logdebug("Destroying BufferChunk at %p\n", chunk); self->firstChunk = chunk->next; mbuf_destroy(chunk->mbuf); pthread_mutex_destroy(&chunk->lock); oml_free(chunk); } mbuf_destroy(self->meta_buf); mbuf_destroy(self->read_buf); pthread_cond_destroy(&self->semaphore); pthread_mutex_destroy(&self->meta_lock); pthread_mutex_destroy(&self->lock); return 0; }
/** Deallocate memory for a TimerInt * \param timer TimerInt to deallocate * \see eventloop_every, eventloop_timer_stop */ static void eventloop_timer_free(TimerInt* timer) { if (!timer) { o_log(O_LOG_DEBUG, "EventLoop: %s: Trying to free NULL pointer\n", __FUNCTION__); } else { oml_free(timer); } }
/** Called to write into the socket * \see oml_outs_write_f * * If the connection needs to be re-established, header is sent first, then buffer, * * \see \see open_socket, socket_write */ static ssize_t net_stream_write(OmlOutStream* hdl, uint8_t* buffer, size_t length, uint8_t* header, size_t header_length) { OmlNetOutStream* self = (OmlNetOutStream*)hdl; size_t count; /* The header can be NULL, but header_length MUST be 0 in that case */ assert(header || !header_length); /* Initialise the socket the first time */ while (self->socket == NULL) { logdebug ("%s: Connecting to server\n", self->dest); if (!open_socket(self)) { logdebug("%s: Connection attempt failed\n", self->dest); return 0; } } /* If the underlying socket has registered a disconnection, it will reconnect on its own * however, we need to check it to make sure we send the headers before anything else */ if(socket_is_disconnected(self->socket)) { self->header_written = 0; } out_stream_write_header(hdl, socket_write, header, header_length); if(o_log_level_active(O_LOG_DEBUG4)) { char *out = to_octets(buffer, length); logdebug("%s: Sending data %s\n", self->dest, out); oml_free(out); } count = socket_write(hdl, buffer, length); return count; }
void msg_queue_destroy (struct msg_queue *queue) { while (queue->length > 0) msg_queue_remove (queue); oml_free (queue); }
/** Close an OmlFileOutStream's output file * \param hdl pointer to the OmlFileOutStream * \return amount of data written, or -1 on error */ static int file_stream_close(OmlOutStream* hdl) { OmlFileOutStream* self = (OmlFileOutStream*)hdl; int ret = -1; logdebug("Destroying OmlFileOutStream to file %s at %p\n", self->dest, self); if (self->f != NULL) { ret = fclose(self->f); self->f = NULL; } oml_free(self->dest); oml_free(self); return ret; }
/** Close an output stream and destroy the objects. * * \param instance handle (i.e., pointer) to a BufferedWriter */ void bw_close(BufferedWriter* instance) { int *retval; BufferedWriter *self = (BufferedWriter*)instance; if(!self) { return; } if (oml_lock (&self->lock, __FUNCTION__)) { return; } self->active = 0; loginfo ("%s: Waiting for buffered queue thread to drain...\n", self->outStream->dest); pthread_cond_signal (&self->semaphore); oml_unlock (&self->lock, __FUNCTION__); if(pthread_join (self->readerThread, (void**)&retval)) { logwarn ("%s: Cannot join buffered queue reader thread: %s\n", self->outStream->dest, strerror(errno)); } else { if (1 == *retval) { logdebug ("%s: Buffered queue fully drained\n", self->outStream->dest); } else { logerror ("%s: Buffered queue did not fully drain\n", self->outStream->dest, *retval); } } self->outStream->close(self->outStream); destroyBufferChain(self); oml_free(self); }
/** Called to close the socket * \see oml_outs_close_f */ static int net_stream_close(OmlOutStream* stream) { OmlNetOutStream* self = (OmlNetOutStream*)stream; logdebug("%s: Destroying OmlNetOutStream at %p\n", self->dest, self); if (self->socket != 0) { socket_close(self->socket); self->socket = NULL; } oml_free(self->dest); oml_free(self->host); oml_free(self->protocol); oml_free(self->service); oml_free(self); return 0; }
int main(int argc, const char *argv[]) { int c, i, ret; /* Reconstruct command line */ size_t cmdline_len = 0; for(i = 0; i < argc; i++) { cmdline_len += strlen(argv[i]) + 1; } char *cmdline = oml_malloc(cmdline_len); cmdline[0] = '\0'; for(i = 0; i < argc; i++) { strncat(cmdline, argv[i], cmdline_len); cmdline_len -= strlen(argv[i]); strncat(cmdline, " ", cmdline_len); cmdline_len--; } /* Initialize OML */ if((ret = omlc_init("generator", &argc, argv, NULL)) < 0) { logerror("Could not initialise OML\n"); return -1; } /* Parse command line arguments */ poptContext optCon = poptGetContext(NULL, argc, argv, options, 0); /* options is defined in generator_popt.h */ while ((c = poptGetNextOpt(optCon)) > 0) {} /* Initialise measurement points and start OML */ oml_register_mps(); /* Defined in generator_oml.h */ if(omlc_start()) { logerror("Could not start OML\n"); return -1; } /* Inject some metadata about this application */ OmlValueU v; omlc_zero(v); omlc_set_string(v, PACKAGE_NAME); omlc_inject_metadata(NULL, "appname", &v, OML_STRING_VALUE, NULL); omlc_set_string(v, PACKAGE_VERSION); omlc_inject_metadata(NULL, "version", &v, OML_STRING_VALUE, NULL); omlc_set_string(v, cmdline); omlc_inject_metadata(NULL, "cmdline", &v, OML_STRING_VALUE, NULL); omlc_reset_string(v); oml_free(cmdline); /* Inject measurements */ run(g_opts, g_oml_mps_generator); /* Do some work and injections, see above */ omlc_close(); return 0; }
/** Terminate Channel and free its allocated memory * * The file descriptor in ch->socket is *NOT* cleaned up here, as all Channels are created through eventloop_on_* functions which first argument is a Socket, socket or file descriptor. The caller of these functions is in charge of cleaning * * \param ch Channel to terminate and free * * \see channel_new * \see oml_free */ static void channel_free( Channel *ch ) { if (!ch) { o_log(O_LOG_DEBUG, "EventLoop: %s: Trying to free NULL pointer\n", __FUNCTION__); } else { oml_free(ch); } }
/** Destroy a filter and free its memory. * * This function is designed so it can be used in a while loop to clean up the * entire linked list: * * while( (f=destroy_ms(f)) ); * * \param f pointer to the filter to destroy * \returns f->next (can be NULL) */ OmlFilter *destroy_filter(OmlFilter* f) { OmlFilter *next; if (!f) return NULL; logdebug("Destroying filter %s at %p\n", f->name, f); next = f->next; if(f->result) { oml_value_array_reset(f->result, f->output_count); oml_free(f->result); } if(f->instance_data) oml_free(f->instance_data); oml_free(f); return next; }
/* * Destroy a table in a database, by free all allocated data * structures. Does not release the table in the backend adapter. */ void database_table_free(Database *database, DbTable *table) { if (database && table) { logdebug("%s: Freeing table '%s'\n", database->name, table->schema->name); schema_free (table->schema); oml_free(table); } else { logwarn("%s: Tried to free a NULL table (or database was NULL).\n", (database ? database->name : "NONE")); } }
/** Create the adapter structure for a table. * * Create a new table in the database, with given schema. Register * the table with the database, so that database_find_table () will * find it. Return a pointer to the table, or NULL on error. * * The schema is deep copied, so the caller can safely free the * schema. * * Note: this function does NOT issue the SQL required to create the * table in the actual storage backend. * * \param database Database to add the DbTable to * \param schema schema structure for that tables * \return an oml_malloc'd DbTable (already added to database), or NULL on error * * \see database_find_table, schema_copy, database_release */ DbTable* database_create_table (Database *database, const struct schema *schema) { DbTable *table = oml_malloc (sizeof (DbTable)); if (!table) return NULL; table->schema = schema_copy (schema); if (!table->schema) { oml_free (table); return NULL; } table->next = database->first_table; database->first_table = table; return table; }
/** Eventloop callback called when a new connection is received on a listening Socket. * * This function accept()s the connection, and creates a SocketInt to wrap * the underlying system socket. It then runs the user-supplied callback * (passed to socket_server_new() when creating the listening Socket) on this * new object, passing it the handle (passed to socket_server_new( too)) * * \param source source from which the event was received (e.g., an OComm Channel) * \param handle pointer to opaque data passed when creating the listening Socket */ static void on_client_connect(SockEvtSource* source, void* handle) { (void)source; // FIXME: Check why source parameter is unused char host[ADDRLEN], serv[SERVLEN]; size_t namesize; *host = 0; *serv = 0; socklen_t cli_len; SocketInt* self = (SocketInt*)handle; SocketInt* newSock = socket_initialize(NULL); cli_len = sizeof(newSock->servAddr.sa_stor); newSock->sockfd = accept(self->sockfd, &newSock->servAddr.sa, &cli_len); if (newSock->sockfd < 0) { o_log(O_LOG_ERROR, "socket(%s): Error on accept: %s\n", self->name, strerror(errno)); oml_free(newSock); return; } /* XXX: Duplicated somewhat with socket_in_new and s_connect */ if (!getnameinfo(&newSock->servAddr.sa, cli_len, host, ADDRLEN, serv, SERVLEN, NI_NUMERICHOST|NI_NUMERICSERV)) { namesize = strlen(host) + strlen(serv) + 3 + 1; newSock->name = oml_realloc(newSock->name, namesize); snprintf(newSock->name, namesize, "[%s]:%s", host, serv); } else { namesize = strlen(host) + 4 + 10 + 1; /* XXX: 10 is arbitrarily chosen for the number of characters in sockfd's decimal representation */ newSock->name = oml_realloc(newSock->name, namesize); snprintf(newSock->name, namesize, "%s-io:%d", self->name, newSock->sockfd); o_log(O_LOG_WARN, "socket(%s): Error resolving new client source, defaulting to %s: %s\n", self->name, newSock->name, strerror(errno)); } if (self->connect_callback) { self->connect_callback((Socket*)newSock, self->connect_handle); } }
/** Function called to close the writer and free its allocated objects. * \see oml_writer_close */ static OmlWriter* owb_close(OmlWriter* writer) { OmlWriter *next; if(!writer) { return NULL; } OmlBinWriter *self = (OmlBinWriter*) writer; next = self->next; // Blocks until the buffered writer drains bw_close (self->bufferedWriter); oml_free(self); return next; }
/** One client no longer uses this database. * If this was the last client checking out, close database. * \param self the database to release * \see db_adapter_release */ void database_release(Database* self) { if (self == NULL) { logerror("NONE: Trying to release a NULL database.\n"); return; } if (--self->ref_count > 0) return; // still in use // unlink DB Database* db_p = first_db; Database* prev_p = NULL; while (db_p != NULL && db_p != self) { prev_p = db_p; db_p = db_p->next; } if (db_p == NULL) { logerror("%s: Trying to release an unknown database\n", self->name); return; } if (prev_p == NULL) first_db = self->next; // was first else prev_p->next = self->next; // no longer needed DbTable* t_p = self->first_table; while (t_p != NULL) { DbTable* t = t_p->next; /* Release the backend storage for this table */ self->table_free (self, t_p); /* Release the table */ database_table_free(self, t_p); t_p = t; } loginfo ("%s: Closing database\n", self->name); self->release (self); database_hook_send_event(self, HOOK_CMD_DBCLOSED); oml_free(self); }
/** Remove the node at the head of the queue. This operation is O(1). */ void msg_queue_remove (struct msg_queue *queue) { if (queue == NULL || queue->tail == NULL) return; struct msg_queue_node *head = queue->tail->next; assert (head != NULL); /* Unlink the head */ queue->length--; if (queue->length == 0) queue->tail = NULL; else queue->tail->next = head->next; oml_free (head); }
/** Create a new table description * * The caller should oml_free the returned value when no longer needed. * The schema argument is kept verbatim (no copy). XXX: It should be copied internally. * * \param name name of the table * \param schema MP schema of the table * \return an oml_malloc'd TableDescr, or NULL on error * \see oml_malloc, oml_free */ TableDescr* table_descr_new (const char* name, struct schema* schema) { if (name == NULL) return NULL; /* schema == NULL means metadata table */ char *new_name = oml_strndup (name, strlen (name)); TableDescr* t = oml_malloc (sizeof(TableDescr)); if (t == NULL) { oml_free (new_name); return NULL; } t->name = new_name; t->schema = schema; t->next = NULL; return t; }
/** Try to convert a string to the given OmlValueT and store it an OmlValueU. * * Storage for value should have already been cleared (e.g., with * oml_value_set_type(), oml_value_reset() omlc_reset_string() or * omlc_reset_blob() if appropriate). * * Assumes the destination OmlValueU has been properly reset. * * \param value pointer to output OmlValue * \param type type of data to get from the string * \param value_s input string * \return 0 on success, -1 otherwise (e.g., conversion error) * \see oml_value_from_s, oml_value_from_typed_s * \see oml_value_set_type, oml_value_reset, omlc_reset_string, omlc_reset_blob */ static int oml_value_ut_from_s (OmlValueU *value, OmlValueT type, const char *value_s) { char *s, *eptr; ssize_t n; size_t s_sz, blob_sz, nof_elts, bytes; uint8_t *blob; oml_guid_t c; char *p; char *q; errno = 0; /* Not all paths manipulate errno, so make sure its value is reset */ switch (type) { case OML_LONG_VALUE: logwarn("%s(): OML_LONG_VALUE is deprecated, please use OML_INT32_VALUE instead\n", __FUNCTION__); omlc_set_long (*value, strtol (value_s, NULL, 0)); break; case OML_INT32_VALUE: omlc_set_int32 (*value, strtol (value_s, NULL, 0)); break; case OML_UINT32_VALUE: omlc_set_uint32 (*value, strtoul (value_s, NULL, 0)); break; case OML_INT64_VALUE: omlc_set_int64 (*value, strtoll (value_s, NULL, 0)); break; case OML_UINT64_VALUE: omlc_set_uint64 (*value, strtoull (value_s, NULL, 0)); break; case OML_DOUBLE_VALUE: { omlc_set_double (*value, strtod (value_s, &eptr)); if (eptr == value_s) { omlc_set_double (*value, NAN); } break; } case OML_STRING_VALUE: s = oml_malloc(strlen(value_s)+1); n = backslash_decode(value_s, s); omlc_reset_string(*value); omlc_set_string(*value, s); omlc_set_string_size(*value,n+1); break; case OML_DATETIME_VALUE: s = oml_malloc(strlen(value_s)+1); n = backslash_decode(value_s, s); omlc_reset_string(*value); omlc_set_string(*value, s); omlc_set_string_size(*value,n+1); break; case OML_BLOB_VALUE: omlc_reset_blob(*value); s_sz = base64_validate_string(value_s); if(s_sz != -1) { blob_sz = base64_size_blob(s_sz); blob = oml_malloc(blob_sz); base64_decode_string(s_sz, value_s, blob_sz, blob); omlc_set_blob_ptr(*value, blob); omlc_set_blob_length(*value, blob_sz); omlc_set_blob_size(*value, blob_sz); } break; case OML_GUID_VALUE: omlc_string_to_guid(value_s, &c); omlc_set_guid(*value, c); break; case OML_BOOL_VALUE: omlc_set_bool(*value, oml_value_string_to_bool(value_s)); break; case OML_VECTOR_DOUBLE_VALUE: omlc_reset_vector(*value); nof_elts = strtod(value_s, &p); if(p - value_s) { size_t i, bytes; double *elts = oml_calloc(nof_elts, sizeof(double)); if(elts) { for(i = 0; i < nof_elts; i++) { elts[i] = strtod(p, &q); if(q - p) p = q; else { oml_free(elts); logerror("%s(): bad [double] vector element '%s'\n", __FUNCTION__, p); return -1; } } bytes = nof_elts * sizeof(double); omlc_set_vector_ptr(*value, elts); omlc_set_vector_length(*value, bytes); omlc_set_vector_size(*value, bytes); omlc_set_vector_nof_elts(*value, nof_elts); omlc_set_vector_elt_size(*value, sizeof(double)); } else { logerror("%s(): out of memory reading [double] of size %zu\n", __FUNCTION__, nof_elts); return -1; } } else { logerror("%s(): bad [double] size '%s'\n", __FUNCTION__, value_s); return -1; } break; case OML_VECTOR_INT32_VALUE: omlc_reset_vector(*value); nof_elts = strtol(value_s, &p, 0); if(p - value_s) { size_t i; int32_t *elts = oml_calloc(nof_elts, sizeof(int32_t)); if(elts) { for(i = 0; i < nof_elts; i++) { elts[i] = strtol(p, &q, 0); if(q - p) p = q; else { oml_free(elts); logerror("%s(): bad [int32] vector element '%s'\n", __FUNCTION__, p); return -1; } } bytes = nof_elts * sizeof(int32_t); omlc_set_vector_ptr(*value, elts); omlc_set_vector_length(*value, bytes); omlc_set_vector_size(*value, bytes); omlc_set_vector_nof_elts(*value, nof_elts); omlc_set_vector_elt_size(*value, sizeof(int32_t)); } else { logerror("%s(): out of memory reading [int32] of size %zu\n", __FUNCTION__, nof_elts); return -1; } } else { logerror("%s(): bad [int32] size '%s'\n", __FUNCTION__, value_s); return -1; } break; case OML_VECTOR_UINT32_VALUE: omlc_reset_vector(*value); nof_elts = strtoul(value_s, &p, 0); if(p - value_s) { size_t i; uint32_t *elts = oml_calloc(nof_elts, sizeof(uint32_t)); if(elts) { for(i = 0; i < nof_elts; i++) { elts[i] = strtoul(p, &q, 0); if(q - p) p = q; else { oml_free(elts); logerror("%s(): bad [uint32] vector element '%s'\n", __FUNCTION__, p); return -1; } } bytes = nof_elts * sizeof(uint32_t); omlc_set_vector_ptr(*value, elts); omlc_set_vector_length(*value, bytes); omlc_set_vector_size(*value, bytes); omlc_set_vector_nof_elts(*value, nof_elts); omlc_set_vector_elt_size(*value, sizeof(uint32_t)); } else { logerror("%s(): out of memory reading [uint32] of size %zu\n", __FUNCTION__, nof_elts); return -1; } } else { logerror("%s(): bad [uint32] size '%s'\n", __FUNCTION__, value_s); return -1; } break; case OML_VECTOR_INT64_VALUE: omlc_reset_vector(*value); nof_elts = strtoll(value_s, &p, 0); if(p - value_s) { size_t i; int64_t *elts = oml_calloc(nof_elts, sizeof(int64_t)); if(elts) { for(i = 0; i < nof_elts; i++) { elts[i] = strtoll(p, &q, 0); if(q - p) p = q; else { oml_free(elts); logerror("%s(): bad [int64] vector element '%s'\n", __FUNCTION__, p); return -1; } } bytes = nof_elts * sizeof(int64_t); omlc_set_vector_ptr(*value, elts); omlc_set_vector_length(*value, bytes); omlc_set_vector_size(*value, bytes); omlc_set_vector_nof_elts(*value, nof_elts); omlc_set_vector_elt_size(*value, sizeof(int64_t)); } else { logerror("%s(): out of memory reading [int64] of size %zu\n", __FUNCTION__, nof_elts); return -1; } } else { logerror("%s(): bad [int64] size '%s'\n", __FUNCTION__, value_s); return -1; } break; case OML_VECTOR_UINT64_VALUE: omlc_reset_vector(*value); nof_elts = strtoull(value_s, &p, 0); if(p - value_s) { size_t i; uint64_t *elts = oml_calloc(nof_elts, sizeof(uint64_t)); if(elts) { for(i = 0; i < nof_elts; i++) { elts[i] = strtoull(p, &q, 0); if(q - p) p = q; else { oml_free(elts); logerror("%s(): bad [uint64] vector element '%s'\n", __FUNCTION__, p); return -1; } } bytes = nof_elts * sizeof(uint64_t); omlc_set_vector_ptr(*value, elts); omlc_set_vector_length(*value, bytes); omlc_set_vector_size(*value, bytes); omlc_set_vector_nof_elts(*value, nof_elts); omlc_set_vector_elt_size(*value, sizeof(uint64_t)); } else { logerror("%s(): out of memory reading [uint64] of size %zu\n", __FUNCTION__, nof_elts); return -1; } } else { logerror("%s(): bad [uint64] size '%s'\n", __FUNCTION__, value_s); return -1; } break; case OML_VECTOR_BOOL_VALUE: omlc_reset_vector(*value); nof_elts = strtoul(value_s, &p, 0); if(p - value_s) { char *n; size_t i; bool *elts = oml_calloc(nof_elts, sizeof(bool)); if(elts) { for(i = 0; i < nof_elts; i++) { char *v = strtok_r(p, " ", &n); if(v) { elts[i] = strncasecmp(v, "false", strlen(v)); p = n; } else { oml_free(elts); logerror("%s(): bad [bool] '%s'\n", __FUNCTION__, p); return -1; } } omlc_set_vector_bool(*value, elts, nof_elts); bytes = nof_elts * sizeof(bool); omlc_set_vector_ptr(*value, elts); omlc_set_vector_length(*value, bytes); omlc_set_vector_size(*value, bytes); omlc_set_vector_nof_elts(*value, nof_elts); omlc_set_vector_elt_size(*value, sizeof(bool)); } else { logerror("%s(): out of memory reading [bool] of size %zu\n", __FUNCTION__, nof_elts); return -1; } } else { logerror("%s(): bad [bool] size '%s'\n", __FUNCTION__, value_s); return -1; } break; default: logerror("%s() for type '%d' not implemented to convert '%s'\n", __FUNCTION__, type, value_s); return -1; } if (errno == ERANGE) { logerror("%s(): underflow or overlow converting value from string '%s'\n", __FUNCTION__, value_s); return -1; } return 0; }
/** Search a Database's registered DbTables for one matchng the given schema. * * If none is found, the table is created. If one is found, but the schema * differs, try to append a number to the name (up to MAX_TABLE_RENAME), create * that table, and update the schema. * * If the table search/creation is successful, the returned DbTable is already * added to the list of the Database. * * \param database Database to search * \param schema schema structure for the table to add * \return a newly created DbTable for that table, or NULL on error * * \see MAX_TABLE_RENAME, database_create_table */ DbTable* database_find_or_create_table(Database *database, struct schema *schema) { if (database == NULL) return NULL; if (schema == NULL) return NULL; DbTable *table = NULL; struct schema *s = schema_copy(schema); int i = 1; int diff = 0, tnlen; tnlen = strlen(schema->name); do { table = database_find_table (database, s->name); if (table) { diff = schema_diff (s, table->schema); if (!diff) { if(database->semantic){ if (database->table_create (database, table, 0)) { logerror ("%s: Couldn't create table '%s'\n", database->name, schema->name); } } schema_free(s); return table; } else if (diff == -1) { logerror ("%s: Schema error table '%s'\n", database->name, s->name); logdebug (" One of the server schema %p or the client schema %p is probably NULL\n", s, table->schema); } else if (diff > 0) { logdebug ("%s: Schema differ for table '%s', at or after column %d\n", database->name, s->name, diff); } if (i == 1) { /* First time we need to increase the size */ /* Add space for 2 characters and null byte, that is up to '_9', with MAX_TABLE_RENAME = 10 */ s->name = oml_realloc(s->name, tnlen + 3); strncpy(s->name, schema->name, tnlen); } snprintf(&s->name[tnlen], 3, "_%d", ++i); } } while(table && diff && (i < MAX_TABLE_RENAME)); if (table && diff) { logerror ("%s: Too many (>%d) tables named '%s_x', giving up. Please use the rename attribute of <mp /> tags.\n", database->name, MAX_TABLE_RENAME, schema->name); schema_free(s); return NULL; } if(i>1) { /* We had to change the table name*/ logwarn("%s: Creating table '%s' for new stream '%s' with incompatible schema\n", database->name, s->name, schema->name); oml_free(schema->name); schema->name = oml_strndup(s->name, tnlen+3); } schema_free(s); /* No table by that name exists, so we create it */ table = database_create_table (database, schema); if (!table) return NULL; if (database->table_create (database, table, 0)) { logerror ("%s: Couldn't create table '%s'\n", database->name, schema->name); /* Unlink the table from the experiment's list */ DbTable* t = database->first_table; if (t == table) database->first_table = t->next; else { while (t && t->next != table) t = t->next; if (t && t->next) t->next = t->next->next; } database_table_free (database, table); return NULL; } return table; }
/** Create OSocket objects bound to name and service. * * This function binds the newly-created socket, but doesn't listen on it just * yet. If name resolves to more than one AF, several sockets are created, * linked through their `next' field. * * \param name name of the object, used for debugging * \param node address or name to listen on; defaults to all if NULL * \param service symbolic name or port number of the service to bind to * \param is_tcp true if TCP, false for UDP XXX: This should be more generic * \return a pointer to a linked list of SocketInt objects, cast as Socket * * \see getaddrinfo(3) */ Socket* socket_in_new(const char* name, const char* node, const char* service, int is_tcp) { SocketInt *self = NULL, *list = NULL; char nameserv[SOCKNAMELEN], *namestr = NULL; size_t namestr_size; struct addrinfo hints, *results, *rp; int ret; *nameserv = 0; memset(&hints, 0, sizeof(struct addrinfo)); hints.ai_socktype = SOCK_STREAM; hints.ai_protocol = IPPROTO_TCP; /* FIXME: We should check self->is_tcp */ hints.ai_flags= AI_PASSIVE; int val = 1; if((ret=getaddrinfo(node, service, &hints, &results))) { o_log(O_LOG_ERROR, "socket(%s): Error resolving %s:%s: %s\n", name, node, service, gai_strerror(ret)); return NULL; } for (rp = results; rp != NULL; rp = rp->ai_next) { sockaddr_get_name((sockaddr_t*)rp->ai_addr, rp->ai_addrlen, nameserv, SOCKNAMELEN); namestr_size = strlen(name) + strlen(nameserv + 2); namestr = oml_realloc(namestr, namestr_size); snprintf(namestr, namestr_size, "%s-%s", name, nameserv); o_log(O_LOG_DEBUG, "socket(%s): Binding to %s (AF %d, proto %d)\n", name, nameserv, rp->ai_family, rp->ai_protocol); if (NULL == (self = (SocketInt*)socket_new(namestr, is_tcp))) { o_log(O_LOG_WARN, "socket(%s): Could allocate Socket to listen on %s: %s\n", self->name, nameserv, strerror(errno)); } else if(0 > (self->sockfd = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol))) { /* It's OK if some AFs fail, we check that in the end */ o_log(O_LOG_DEBUG, "socket(%s): Could not create socket to listen on %s: %s\n", self->name, nameserv, strerror(errno)); socket_free((Socket*)self); } else if(0 != setsockopt(self->sockfd, SOL_SOCKET, SO_REUSEADDR, &val, sizeof(int))){ o_log(O_LOG_WARN, "socket(%s): Could not set option SO_REUSEADDR on socket to listen on %s: %s\n", self->name, nameserv, strerror(errno)); close(self->sockfd); /* XXX: Not optimal: we could reuse the Socket */ socket_free((Socket*)self); } else if (0 != bind(self->sockfd, rp->ai_addr, rp->ai_addrlen)) { o_log(O_LOG_WARN, "socket(%s): Error binding socket to listen on %s: %s\n", self->name, nameserv, strerror(errno)); close(self->sockfd); /* XXX: Not optimal: we could reuse the Socket */ socket_free((Socket*)self); } else { /* The last connected AFs (hence less important according to GAI) are * now at the front, but it's not a big deal as we treat them all * equally (i.e, we're going to listen on them all */ self->next = (Socket*)list; list = self; self = NULL; } } if (namestr) { oml_free(namestr); } freeaddrinfo(results); if (NULL == list) { o_log(O_LOG_ERROR, "socket(%s): Could not create any socket to listen on port %s\n", name, service); } return (Socket*)list; }
/** Parse a collection URI of the form [scheme:][host[:port]][/path]. * * Either host or path are mandatory. * * If under-qualified, the URI scheme is assumed to be 'tcp', the port '3003', * and the rest is used as the host; path is invalid for a tcp URI (only valid * for file). * * \param uri string containing the URI to parse * \param scheme pointer to be updated to a string containing the selected scheme, to be oml_free()'d by the caller * \param host pointer to be updated to a string containing the host, to be oml_free()'d by the caller * \param port pointer to be updated to a string containing the port, to be oml_free()'d by the caller * \param path pointer to be updated to a string containing the path, to be oml_free()'d by the caller * \return 0 on success, -1 otherwise * * \see oml_strndup, oml_free, oml_uri_type, URI_RE, URI_RE_NGROUP */ int parse_uri (const char *uri, const char **scheme, const char **host, const char **port, const char **path) { static regex_t preg; static int preg_valid = 0; char error[80]; size_t nmatch = URI_RE_NGROUP+1; regmatch_t pmatch[nmatch]; int bracket_offset = 0; int ret; char *str; int len, authlen; assert(scheme); assert(host); assert(port); assert(path); *scheme = *host = *port = *path = NULL; /* XXX: static so we only compile it once, but we cannot free it */ if (!preg_valid) { if((ret = regcomp(&preg, URI_RE, REG_EXTENDED))) { regerror(ret , &preg, error, sizeof(error)); logerror("Unable to compile RE /%s/ for URI parsing: %s\n", URI_RE, error); return -1; } preg_valid = 1; } if ((ret = regexec(&preg, uri, nmatch, pmatch, 0))) { regerror(ret , &preg, error, sizeof(error)); logerror("Unable to match uri '%s' against RE /%s/: %s\n", uri, URI_RE, error); return -1; } logdebug("URI '%s' parsed as scheme: '%s', host: '%s', port: '%s', path: '%s'\n", uri, (pmatch[URI_RE_SCHEME].rm_so>=0)?(uri+pmatch[URI_RE_SCHEME].rm_so):"(n/a)", (pmatch[URI_RE_HOST].rm_so>=0)?(uri+pmatch[URI_RE_HOST].rm_so):"(n/a)", (pmatch[URI_RE_PORT].rm_so>=0)?(uri+pmatch[URI_RE_PORT].rm_so):"(n/a)", (pmatch[URI_RE_PATH].rm_so>=0)?(uri+pmatch[URI_RE_PATH].rm_so):"(n/a)" ); if (pmatch[URI_RE_SCHEME].rm_so >= 0) { *scheme = oml_strndup(uri+pmatch[URI_RE_SCHEME].rm_so, pmatch[URI_RE_SCHEME].rm_eo - pmatch[URI_RE_SCHEME].rm_so); } if (pmatch[URI_RE_HOST].rm_so >= 0) { /* Host may contain bracketted IP addresses, clean that up. */ if ('[' == *(uri + pmatch[URI_RE_HOST].rm_so)) { if (']' != *(uri + pmatch[URI_RE_HOST].rm_eo - 1)) { logerror("Unbalanced brackets in host part of '%s' (%d %d): %c\n", uri, pmatch[URI_RE_HOST].rm_so, pmatch[URI_RE_HOST].rm_eo, uri + pmatch[URI_RE_HOST].rm_eo - 1); return -1; } bracket_offset += 1; } *host = oml_strndup(uri+pmatch[URI_RE_HOST].rm_so + bracket_offset, pmatch[URI_RE_HOST].rm_eo - pmatch[URI_RE_HOST].rm_so - 2 * bracket_offset); } if (pmatch[URI_RE_PORT].rm_so >= 0) { *port = oml_strndup(uri+pmatch[URI_RE_PORT].rm_so, pmatch[URI_RE_PORT].rm_eo - pmatch[URI_RE_PORT].rm_so); } if (pmatch[URI_RE_PATH].rm_so >= 0) { *path= oml_strndup(uri+pmatch[URI_RE_PATH].rm_so, pmatch[URI_RE_PATH].rm_eo - pmatch[URI_RE_PATH].rm_so); /*if(!strncmp(*path, "::", 2) || oml_uri_is_network(oml_uri_type(*path))) { logwarn("Parsing URI '%s' as 'file:%s'\n", uri, *path); }*/ } /* Fixup parsing inconsistencies (mainly due to optionality of //) so we don't break old behaviours */ if (!(*scheme)) { *scheme = oml_strndup("tcp", 3); } if(oml_uri_is_network(oml_uri_type(*scheme))) { if(!(*host)) { logerror("Network URI '%s' does not contain host" " (did you forget to put literal IPv6 addresses in brackets?)'\n", uri); return -1; } if (pmatch[URI_RE_SCHEME].rm_so >= 0 && pmatch[URI_RE_HOST].rm_so >= 0 && pmatch[URI_RE_AUTHORITY_WITH_SLASHES].rm_so == pmatch[URI_RE_AUTHORITY].rm_so) { logwarn("Network URI without a double slash before authority part is deprecated: '%s' should be '%s://%s%s%s'\n", uri, *scheme, *host, *port?":":"", *port?*port:""); } if(!(*port)) { *port = oml_strndup(DEF_PORT_STRING, sizeof(DEF_PORT_STRING)); } } else if ((*host) && oml_uri_is_file(oml_uri_type(*scheme))) { /* We split the filename into host and path in a URI without host; * concatenate them back together, adding all the leading slashes that were initially present */ authlen = len = pmatch[URI_RE_AUTHORITY_WITH_SLASHES].rm_eo - pmatch[URI_RE_AUTHORITY_WITH_SLASHES].rm_so; if (*path) { len += strlen(*path); } str = oml_malloc(len + 1); if (!str) { logerror("Memory error parsing URI '%s'\n", uri); return -1; } *str=0; strncat(str, uri+pmatch[URI_RE_AUTHORITY_WITH_SLASHES].rm_so, authlen); if (*path) { len -= authlen; strncat(str, *path, len); } oml_free((void*)*host); *host = NULL; oml_free((void*)*path); *path = str; } return 0; }