/** Create a new out stream for sending over the network * \param transport string representing the protocol used to establish the connection (oml_strndup()'d locally) * \param hostname string representing the host to connect to (oml_strndup()'d locally) * \param service symbolic name or port number of the service to connect to (oml_strndup()'d locally) * \return a new OmlOutStream instance * * \see oml_strndup */ OmlOutStream* net_stream_new(const char *transport, const char *hostname, const char *service) { MString *dest; assert(transport != NULL && hostname != NULL && service != NULL); OmlNetOutStream* self = (OmlNetOutStream *)oml_malloc(sizeof(OmlNetOutStream)); memset(self, 0, sizeof(OmlNetOutStream)); dest = mstring_create(); mstring_sprintf(dest, "%s://%s:%s", transport, hostname, service); self->dest = (char*)oml_strndup (mstring_buf(dest), mstring_len(dest)); mstring_delete(dest); self->protocol = (char*)oml_strndup (transport, strlen (transport)); self->host = (char*)oml_strndup (hostname, strlen (hostname)); self->service = (char*)oml_strndup (service, strlen (service)); logdebug("%s: Created OmlNetOutStream\n", self->dest); socket_set_non_blocking_mode(0); /* // Now see if we can connect to server */ /* if (! open_socket(self)) { */ /* free(self); */ /* return NULL; */ /* } */ self->write = net_stream_write; self->close = net_stream_close; return (OmlOutStream*)self; }
/** Create and initialise a +Client+ structure to represent a single client. * * \param client_sock the socket associated to the client transmission * (from libocomm). The client_sock should be attached to an active * client that has been accepted by the server socket. * * \param page_size the page size for the underlying memory store for * buffering received measurements. * \param file_name save measurements to a file with this name. * \param server_port the port of the downstream OML server * \param server_address the address of the downstream OML Server * * \return a new Client structure */ Client* client_new (Socket* client_sock, int page_size, char* file_name, int server_port, char* server_address) { Client* self = (Client *)oml_malloc(sizeof(Client)); memset(self, 0, sizeof(Client)); self->state = C_HEADER; self->downstream_port = server_port; self->downstream_addr = oml_strndup (server_address, strlen (server_address)); self->mbuf = mbuf_create (); self->headers = NULL; self->msg_start = dummy_read_msg_start; self->messages = msg_queue_create (); self->cbuf = cbuf_create (page_size); self->file = fopen(file_name, "wa"); self->file_name = oml_strndup (file_name, strlen (file_name)); self->recv_socket = client_sock; /* FIXME: Return value checking */ pthread_mutex_init (&self->mutex, NULL); pthread_cond_init (&self->condvar, NULL); return self; }
/** Create a new out stream for writing into a local file. * * \param file destination file (oml_strndup()'d locally) * \return a new OmlOutStream instance * * \see oml_strndup */ OmlOutStream* file_stream_new(const char *file) { MString *dest; OmlFileOutStream* self = (OmlFileOutStream *)oml_malloc(sizeof(OmlFileOutStream)); memset(self, 0, sizeof(OmlFileOutStream)); loginfo ("File_stream: opening local storage file '%s'\n", file); if (strcmp(file, "stdout") == 0 || strcmp(file, "-") == 0) { self->f = stdout; } else { if ((self->f = fopen(file, "a+")) == NULL) { logerror ("Can't open local storage file '%s'\n", file); return 0; } } dest = mstring_create(); mstring_sprintf(dest, "file:%s", file); self->dest = (char*)oml_strndup (mstring_buf(dest), mstring_len(dest)); mstring_delete(dest); self->write = file_stream_write; self->close = file_stream_close; return (OmlOutStream*)self; }
/** Create a new outgoing TCP Socket. * * \param name name of this Socket, for debugging purposes * \param dest DNS name or address of the destination * \param service symbolic name or port number of the service to connect to * \return a newly-allocated Socket, or NULL on error */ Socket* socket_tcp_out_new(const char* name, const char* dest, const char* service) { SocketInt* self; if (dest == NULL) { o_log(O_LOG_ERROR, "socket(%s): Missing destination\n", name); return NULL; } if ((self = (SocketInt*)socket_new(name, TRUE)) == NULL) { return NULL; } self->dest = oml_strndup(dest, strlen(dest)); self->service = oml_strndup(service, strlen(service)); // eventloop_on_out_channel((Socket*)self, on_self_connected, NULL); return (Socket*)self; }
/** Create a new instance of the Socket object (SocketInt). * * The sendto and get_sockfd are set to the default socket_sendto() and * socket_get_sockfd() functions, respectively. * * \param name name of the object, used for debugging * \return a pointer to the SocketInt object */ static SocketInt* socket_initialize(const char* name) { const char* sock_name = (name != NULL)?name:"UNKNOWN"; SocketInt* self = (SocketInt *)oml_malloc(sizeof(SocketInt)); memset(self, 0, sizeof(SocketInt)); self->sockfd = -1; self->name = oml_strndup(sock_name, strlen(sock_name)); self->sendto = socket_sendto; self->get_sockfd = socket_get_sockfd; return self; }
/** 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; }
/** 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; }
/** 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; }