str mnstr_socket_wastreamwrap(Stream *S, int *socket, str *name) { stream *s; if ((s = socket_wastream(*socket, *name)) == NULL || mnstr_errnr(s)) { int errnr = mnstr_errnr(s); if (s) mnstr_destroy(s); throw(IO, "streams.open", "could not open socket: %s", strerror(errnr)); } else { *(stream**)S = s; } return MAL_SUCCEED; }
/* Sends command for database to merovingian listening at host and port. * If host is a path, and port is -1, a UNIX socket connection for host * is opened. The response of merovingian is returned as a malloced * string. If wait is set to a non-zero value, this function will only * return after it has seen an EOF from the server. This is useful with * multi-line responses, but can lock up for single line responses where * the server allows pipelining (and hence doesn't close the * connection). */ char* control_send( char** ret, char* host, int port, char* database, char* command, char wait, char* pass) { char sbuf[8096]; char rbuf[8096]; char *buf; int sock = -1; ssize_t len; stream *fdin = NULL; stream *fdout = NULL; *ret = NULL; /* gets overwritten in case of success */ if (port == -1) { struct sockaddr_un server; /* UNIX socket connect */ if ((sock = socket(PF_UNIX, SOCK_STREAM, 0)) == -1) { snprintf(sbuf, sizeof(sbuf), "cannot open connection: %s", strerror(errno)); return(strdup(sbuf)); } memset(&server, 0, sizeof(struct sockaddr_un)); server.sun_family = AF_UNIX; strncpy(server.sun_path, host, sizeof(server.sun_path) - 1); if (connect(sock, (SOCKPTR) &server, sizeof(struct sockaddr_un)) == -1) { snprintf(sbuf, sizeof(sbuf), "cannot connect: %s", strerror(errno)); close(sock); return(strdup(sbuf)); } } else { struct sockaddr_in server; struct hostent *hp; char ver = 0; char *p; /* TCP socket connect */ if ((sock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP)) == -1) { snprintf(sbuf, sizeof(sbuf), "cannot open connection: %s", strerror(errno)); return(strdup(sbuf)); } hp = gethostbyname(host); if (hp == NULL) { snprintf(sbuf, sizeof(sbuf), "cannot lookup hostname: %s", hstrerror(h_errno)); close(sock); return(strdup(sbuf)); } memset(&server, 0, sizeof(struct sockaddr_in)); server.sin_family = hp->h_addrtype; memcpy(&server.sin_addr, hp->h_addr_list[0], hp->h_length); server.sin_port = htons((unsigned short) (port & 0xFFFF)); if (connect(sock, (SOCKPTR) &server, sizeof(struct sockaddr_in)) == -1) { snprintf(sbuf, sizeof(sbuf), "cannot connect: %s", strerror(errno)); close(sock); return(strdup(sbuf)); } /* try reading length */ len = recv(sock, rbuf, 2, 0); if (len == 2) len += recv(sock, rbuf + len, sizeof(rbuf) - len - 1, 0); /* perform login ritual */ if (len <= 2) { snprintf(sbuf, sizeof(sbuf), "no response from monetdbd"); close(sock); return(strdup(sbuf)); } rbuf[len] = 0; /* we only understand merovingian:1 and :2 (backwards compat * <=Aug2011) and mapi v9 on merovingian */ if (strncmp(rbuf, "merovingian:1:", strlen("merovingian:1:")) == 0) { buf = rbuf + strlen("merovingian:1:"); ver = 1; } else if (strncmp(rbuf, "merovingian:2:", strlen("merovingian:2:")) == 0) { buf = rbuf + strlen("merovingian:2:"); ver = 2; } else if (strstr(rbuf + 2, ":merovingian:9:") != NULL) { buf = rbuf + 2; ver = 9; fdin = block_stream(socket_rastream(sock, "client in")); fdout = block_stream(socket_wastream(sock, "client out")); } else { if (len > 2 && (strstr(rbuf + 2, ":BIG:") != NULL || strstr(rbuf + 2, ":LIT:") != NULL)) { snprintf(sbuf, sizeof(sbuf), "cannot connect: " "server looks like a mapi server, " "are you connecting to an mserver directly " "instead of monetdbd?"); } else { snprintf(sbuf, sizeof(sbuf), "cannot connect: " "unsupported monetdbd server"); } close(sock); return(strdup(sbuf)); } switch (ver) { case 1: case 2: /* we never really used the mode specifier of v2 */ p = strchr(buf, ':'); if (p != NULL) *p = '\0'; p = control_hash(pass, buf); len = snprintf(sbuf, sizeof(sbuf), "%s%s\n", p, ver == 2 ? ":control" : ""); len = send(sock, sbuf, len, 0); free(p); if (len == -1) { close(sock); return(strdup("cannot send challenge response to server")); } break; case 9: { char *chal = NULL; char *algos = NULL; char *shash = NULL; char *phash = NULL; char *algsv[] = { "RIPEMD160", "SHA256", "SHA1", "MD5", NULL }; char **algs = algsv; /* buf at this point looks like * "challenge:servertype:protover:algos:endian:hash:" */ chal = buf; /* chal */ p = strchr(chal, ':'); if (p == NULL) { snprintf(sbuf, sizeof(sbuf), "cannot connect: " "invalid challenge from monetdbd server"); close_stream(fdout); close_stream(fdin); return(strdup(sbuf)); } *p++ = '\0'; /* servertype */ p = strchr(p, ':'); if (p == NULL) { snprintf(sbuf, sizeof(sbuf), "cannot connect: " "invalid challenge from monetdbd server"); close_stream(fdout); close_stream(fdin); return(strdup(sbuf)); } *p++ = '\0'; /* protover */ p = strchr(p, ':'); if (p == NULL) { snprintf(sbuf, sizeof(sbuf), "cannot connect: " "invalid challenge from monetdbd server"); close_stream(fdout); close_stream(fdin); return(strdup(sbuf)); } *p++ = '\0'; /* algos */ algos = p; p = strchr(p, ':'); if (p == NULL) { snprintf(sbuf, sizeof(sbuf), "cannot connect: " "invalid challenge from monetdbd server"); close_stream(fdout); close_stream(fdin); return(strdup(sbuf)); } *p++ = '\0'; /* endian */ p = strchr(p, ':'); if (p == NULL) { snprintf(sbuf, sizeof(sbuf), "cannot connect: " "invalid challenge from monetdbd server"); close_stream(fdout); close_stream(fdin); return(strdup(sbuf)); } *p++ = '\0'; /* hash */ shash = p; p = strchr(p, ':'); if (p == NULL) { snprintf(sbuf, sizeof(sbuf), "cannot connect: " "invalid challenge from monetdbd server"); close_stream(fdout); close_stream(fdin); return(strdup(sbuf)); } *p = '\0'; /* we first need to hash our password in the form the * server stores it too */ if (strcmp(shash, "RIPEMD160") == 0) { phash = mcrypt_RIPEMD160Sum(pass, strlen(pass)); } else if (strcmp(shash, "SHA512") == 0) { phash = mcrypt_SHA512Sum(pass, strlen(pass)); } else if (strcmp(shash, "SHA384") == 0) { phash = mcrypt_SHA384Sum(pass, strlen(pass)); } else if (strcmp(shash, "SHA256") == 0) { phash = mcrypt_SHA256Sum(pass, strlen(pass)); } else if (strcmp(shash, "SHA224") == 0) { phash = mcrypt_SHA224Sum(pass, strlen(pass)); } else if (strcmp(shash, "SHA1") == 0) { phash = mcrypt_SHA1Sum(pass, strlen(pass)); } else if (strcmp(shash, "MD5") == 0) { phash = mcrypt_MD5Sum(pass, strlen(pass)); } else { snprintf(sbuf, sizeof(sbuf), "cannot connect: " "monetdbd server requires unknown hash: %s", shash); close_stream(fdout); close_stream(fdin); return(strdup(sbuf)); } /* now hash the password hash with the provided * challenge */ for (; *algs != NULL; algs++) { /* TODO: make this actually obey the separation by * commas, and only allow full matches */ if (strstr(algos, *algs) != NULL) { p = mcrypt_hashPassword(*algs, phash, chal); if (p == NULL) continue; mnstr_printf(fdout, "BIG:monetdb:{%s}%s:control:merovingian:\n", *algs, p); mnstr_flush(fdout); free(p); break; } } free(phash); if (p == NULL) { /* the server doesn't support what we can */ snprintf(sbuf, sizeof(sbuf), "cannot connect: " "unsupported hash algoritms: %s", algos); close_stream(fdout); close_stream(fdin); return(strdup(sbuf)); } } } if (fdin != NULL) { /* stream.h is sooo broken :( */ memset(rbuf, '\0', sizeof(rbuf)); if ((len = mnstr_read_block(fdin, rbuf, sizeof(rbuf) - 1, 1)) < 0) { close_stream(fdout); close_stream(fdin); return(strdup("no response from monetdbd after login")); } rbuf[len - 1] = '\0'; } else { if ((len = recv(sock, rbuf, sizeof(rbuf), 0)) <= 0) { close(sock); return(strdup("no response from monetdbd after login")); } rbuf[len - 1] = '\0'; } if (strcmp(rbuf, "=OK") != 0 && strcmp(rbuf, "OK") != 0) { buf = rbuf; if (*buf == '!') buf++; if (fdin != NULL) { close_stream(fdout); close_stream(fdin); } else { close(sock); } return(strdup(buf)); } } if (fdout != NULL) { mnstr_printf(fdout, "%s %s\n", database, command); mnstr_flush(fdout); } else { len = snprintf(sbuf, sizeof(sbuf), "%s %s\n", database, command); if (send(sock, sbuf, len, 0) == -1) { close(sock); return(strdup("failed to send control command to server")); } } if (wait != 0) { size_t buflen = sizeof(sbuf); size_t bufpos = 0; char *bufp; bufp = buf = malloc(sizeof(char) * buflen); if (buf == NULL) { if (fdin != NULL) { close_stream(fdin); close_stream(fdout); } else { close(sock); } return(strdup("failed to allocate memory")); } while (1) { if (fdin != NULL) { /* stream.h is sooo broken :( */ memset(buf + bufpos, '\0', buflen - bufpos); len = mnstr_read_block(fdin, buf + bufpos, buflen - bufpos - 1, 1); if (len >= 0) len = strlen(buf + bufpos); } else { len = recv(sock, buf + bufpos, buflen - bufpos, 0); } if (len <= 0) break; if ((size_t)len == buflen - bufpos) { buflen *= 2; bufp = realloc(buf, sizeof(char) * buflen); if (bufp == NULL) { free(buf); if (fdin != NULL) { close_stream(fdin); close_stream(fdout); } else { close(sock); } return(strdup("failed to allocate more memory")); } buf = bufp; } bufpos += (size_t)len; } if (bufpos == 0) { if (fdin != NULL) { close_stream(fdin); close_stream(fdout); } else { close(sock); } free(buf); return(strdup("incomplete response from monetdbd")); } buf[bufpos - 1] = '\0'; if (fdin) { /* strip out protocol = */ memmove(bufp, bufp + 1, strlen(bufp + 1) + 1); while ((bufp = strstr(bufp, "\n=")) != NULL) memmove(bufp + 1, bufp + 2, strlen(bufp + 2) + 1); } *ret = buf; } else { if (fdin != NULL) { if (mnstr_read_block(fdin, rbuf, sizeof(rbuf) - 1, 1) < 0) { close_stream(fdin); close_stream(fdout); return(strdup("incomplete response from monetdbd")); } rbuf[strlen(rbuf) - 1] = '\0'; *ret = strdup(rbuf + 1); } else { if ((len = recv(sock, rbuf, sizeof(rbuf), 0)) <= 0) { close(sock); return(strdup("incomplete response from monetdbd")); } rbuf[len - 1] = '\0'; *ret = strdup(rbuf); } } if (fdin != NULL) { close_stream(fdin); close_stream(fdout); } else { close(sock); } return(NULL); }
int main(int argc, char **argv) { MT_Id pid; int i, j = 0; char *err = NULL; char name[MYBUFSIZ + 1]; char hostname[1024]; Sensor se = NULL; static SOCKET sockfd; static struct option long_options[18] = { { "increment", 0, 0, 'i' }, { "batch", 1, 0, 'b' }, { "columns", 1, 0, 'c' }, { "client", 0, 0, 'c' }, { "port", 1, 0, 'p' }, { "protocol", 1, 0, 'p' }, { "timestamp", 0, 0, 't' }, { "time", 1, 0, 't' }, { "events", 1, 0, 'e' }, { "sensor", 1, 0, 's' }, { "server", 0, 0, 's' }, { "replay", 0, 0, 'r' }, { "delay", 1, 0, 'd' }, { "file", 1, 0, 'f' }, { "host", 1, 0, 'h' }, { "trace", 0, 0, 't' }, { "help", 1, 0, '?' }, { 0, 0, 0, 0 } }; THRdata[0] = (void *) file_wastream(stdout, "stdout"); THRdata[1] = (void *) file_rastream(stdin, "stdin"); for (i = 0; i < THREADS; i++) { GDKthreads[i].tid = i + 1; } for (;;) { int option_index = 0; int c = getopt_long(argc, argv, "i:b:c:c:p:p:t:t:e:s:s:r:d:f:h:t:?:0", long_options, &option_index); if (c == -1) break; switch (c) { case 'b': batchsize = optarg ? atol(optarg) : -1; if (batchsize <= 0) { mnstr_printf(SEout, "Illegal batch %d\n", batchsize); exit(0); } break; case 'c': if (strcmp(long_options[option_index].name, "client") == 0) { server = 0; break; } columns = optarg ? atol(optarg) : -1; if (columns <= 0) { mnstr_printf(SEout, "Illegal columns %d\n", columns); exit(0); } break; case 'd': delay = optarg ? atol(optarg) : -1; if (delay < 0) { mnstr_printf(SEout, "Illegal delay %d\n", delay); exit(0); } break; case 'i': autoincrement = optarg ? atol(optarg) : 0; if (autoincrement < 0) { mnstr_printf(SEout, "Illegal increment %d\n", autoincrement); exit(0); } break; case 't': if (strcmp(long_options[option_index].name, "timestamp") == 0) { timestamp = 1; break; } if (strcmp(long_options[option_index].name, "time") == 0) { timecolumn = optarg ? atol(optarg) : 0; break; } if (strcmp(long_options[option_index].name, "trace") == 0) { trace = optarg ? atol(optarg) : 1; } else { usage(); exit(0); } break; case 'f': datafile = optarg && *optarg? optarg:0; break; case 'e': if (strcmp(long_options[option_index].name, "events") == 0) { events = optarg ? atol(optarg) : -1; if (events < -1) { mnstr_printf(SEout, "illegal events value, reset to -1\n"); events = -1; } else if (events == 0) { mnstr_printf(SEout, "Illegal events value %d\n", events); exit(0); } break; } else { usage(); exit(0); } break; case 'r': replay= 1; break; case 's': if (strcmp(long_options[option_index].name, "sensor") == 0) { sensor = optarg; break; } if (strcmp(long_options[option_index].name, "server") == 0) { server = 1; break; } else { usage(); exit(0); } break; case 'p': if (strcmp(long_options[option_index].name, "protocol") == 0) { char *name= optarg? optarg: "xyz"; if (strcmp(name, "TCP") == 0 || strcmp(name, "tcp") == 0) { protocol = TCP; break; } if (strcmp(name, "UDP") == 0 || strcmp(name, "udp") == 0) { protocol = UDP; break; } if (strcmp(name, "CSV") == 0 || strcmp(name, "csv") == 0) { protocol = CSV; break; } if (strcmp(name, "debug") == 0) { protocol = DEB; break; } } if (strcmp(long_options[option_index].name, "port") == 0) { port = optarg ? atol(optarg) : -1; #ifdef SENSOR_DEBUG mnstr_printf(SEout, "#PORT : %d\n", port); #endif break; } else { usage(); exit(0); } break; case 'h': host = optarg; break; case '?': default: usage(); exit(0); } } signal(SIGABRT, stopSend); #ifdef SIGPIPE signal(SIGPIPE, stopSend); #endif #ifdef SIGHUP signal(SIGHUP, stopSend); #endif signal(SIGTERM, stopSend); signal(SIGINT, stopSend); /* display properties */ if (trace) { mnstr_printf(SEout, "--host=%s\n", host); mnstr_printf(SEout, "--port=%d\n", port); mnstr_printf(SEout, "--sensor=%s\n", sensor); mnstr_printf(SEout, "--columns=%d\n", columns); mnstr_printf(SEout, "--autoincrement=%d\n", autoincrement); mnstr_printf(SEout, "--timestamp=%d\n", timestamp); mnstr_printf(SEout, "--time=%d\n", timecolumn); mnstr_printf(SEout, "--events=%d\n", events); mnstr_printf(SEout, "--batch=%d\n", batchsize); mnstr_printf(SEout, "--replay=%d\n", replay); mnstr_printf(SEout, "--delay=%d\n", delay); mnstr_printf(SEout, "--protocol %s\n", protocolname[protocol]); mnstr_printf(SEout, "--trace=%d\n", trace); mnstr_printf(SEout, "--server=%d\n", server); mnstr_printf(SEout, "--client=%d\n", server); if (datafile) mnstr_printf(SEout, "--input=%s\n", datafile); } estimateOverhead(); strncpy(hostname, host, 1024); if (strcmp(host, "localhost") == 0) gethostname(hostname, 1024); host = hostname; /* * We limit the protocols for the time being to what can be * considered a safe method. */ if (protocol == DEB) { /* save event stream in a file */ Sensor se = SEnew(sensor); if (events == -1 || batchsize != 1) { printf("Provide an event limit using --events=<nr> and --batch=1\n"); return 0; } if (datafile) se->toServer = open_wastream(datafile); else se->toServer = file_wastream(stdout, "stdout"); produceStream(se); } if (protocol == UDP) { Sensor se = SEnew(sensor); se->toServer = udp_wastream(host, port, sensor); if (se->toServer == NULL) { perror("Sensor: Could not open stream"); mnstr_printf(SEout, "#stream %s.%d.%s\n", host, port, sensor); return 0; } produceStream(se); } if (protocol == TCP) { if (server && (err = socket_server_connect(&sockfd, port))) { mnstr_printf(SEout, "#SENSOR:start server:%s\n", err); return 0; } do { int createThread = 0; snprintf(name, MYBUFSIZ - (strlen(sensor) + sizeof(j)), "%s%d", sensor, j++); se = SEnew(name); name[0] = 0; err = NULL; if (server) { #ifdef SENSOR_DEBUG mnstr_printf(SEout, "#listen %s as server is %d \n", se->name, server); #endif err = socket_server_listen(sockfd, &(se->newsockfd)); if (err) { mnstr_printf(SEout, "#SENSOR:server listen:%s\n", err); break; } } else { #ifdef SENSOR_DEBUG mnstr_printf(SEout, "#%s is client \n", se->name); #endif err = socket_client_connect(&(se->newsockfd), host, port); if (err) { mnstr_printf(SEout, "#SENSOR:client start:%s\n", err); break; } } se->toServer = socket_wastream(se->newsockfd, se->name); if (se->toServer == NULL) { perror("Sensor: Could not open stream"); mnstr_printf(SEout, "#stream %s.%d.%s\n", host, port, sensor); socket_close(se->newsockfd); return 0; } if (server) { createThread = MT_create_thread(&pid, (void (*)(void *))produceServerStream, se, MT_THR_DETACHED); #ifdef SENSOR_DEBUG if (createThread) mnstr_printf(SEout, "#Create thread is : %d \n", createThread); #else (void) createThread; #endif } else { /* client part */ produceServerStream(se); } } while (server); if (server) socket_close(sockfd); if (se) shutdown(se->newsockfd, SHUT_RDWR); } return 0; }