/** 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); } }
/** 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; }
/** 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; }