str mnstr_socket_rastreamwrap(Stream *S, int *socket, str *name) { stream *s; if ((s = socket_rastream(*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) { int i; char *err = NULL; /*char name[MYBUFSIZ + 1];*/ char hostname[1024]; static SOCKET sockfd; Actuator ac = NULL; int option_index = 0; static struct option long_options[13] = { { "port", 1, 0, 'p' }, { "actuator", 1, 0, 'a' }, { "active", 0, 0, 'a' }, { "passive", 0, 0, 'p' }, { "statistics", 0, 0, 's' }, { "protocol", 1, 0, 'p' }, { "events", 1, 0, 'e' }, { "host", 1, 0, 'h' }, { "help", 1, 0, '?' }, { "timestamp", 0, 0, 't' }, { "trace", 0, 0, 't' }, { 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, "p:a:a:p:s:p:e:h:?:t:t:0", long_options, &option_index); if (c == -1) break; switch (c) { case 't': if (strcmp(long_options[option_index].name, "trace") == 0) { trace = optarg ? atol(optarg) : 1; } else if (strcmp(long_options[option_index].name, "timestamp") == 0) { timestamp = optarg ? atol(optarg) : 1; } else { usage(); exit(0); } break; case 'e': if (strcmp(long_options[option_index].name, "events") == 0) { events = optarg ? atol(optarg) : 1; } else { usage(); exit(0); } break; case 'a': if (strcmp(long_options[option_index].name, "active") == 0) { mode = ACTIVE; break; } else actuator = optarg ? optarg : "dummy"; break; case 'p': if (strcmp(long_options[option_index].name, "port") == 0) { port = optarg ? atol(optarg) : -1; break; } else if (strcmp(long_options[option_index].name, "passive") == 0) { mode = PASSIVE; break; } else if (strcmp(long_options[option_index].name, "protocol") == 0) { if (strcmp(optarg, "TCP") == 0 || strcmp(optarg, "tcp") == 0) { protocol = TCP; break; } if (strcmp(optarg, "UDP") == 0 || strcmp(optarg, "udp") == 0) { protocol = UDP; break; } } break; case 's': if (strcmp(long_options[option_index].name, "statistics") == 0) { statistics = optarg ? atol(optarg) : 100; break; } else { usage(); exit(0); } break; case 'h': host = optarg; break; case '?': default: usage(); exit(0); } } signal(SIGABRT, stopListening); #ifdef SIGPIPE signal(SIGPIPE, stopListening); #endif #ifdef SIGHUP signal(SIGHUP, stopListening); #endif signal(SIGTERM, stopListening); signal(SIGINT, stopListening); /* display properties */ if (trace) { mnstr_printf(ACout, "--host=%s\n", host); mnstr_printf(ACout, "--port=%d\n", port); mnstr_printf(ACout, "--actuator=%s\n", actuator); mnstr_printf(ACout, "--events=%d\n", events); mnstr_printf(ACout, "--timestamp=%d\n", timestamp); mnstr_printf(ACout, "--statistics=%d\n", statistics); mnstr_printf(ACout, "--%s\n", mode == ACTIVE ? "active" : "passive"); } strncpy(hostname, host, 1024); if (strcmp(host, "localhost") == 0) gethostname(hostname, 1024); host = hostname; ac = ACnew(actuator); /*name[0] = 0;*/ err = NULL; if (mode == PASSIVE) { ac->fromServer = udp_rastream(host, port, actuator); if (ac->fromServer == 0) { mnstr_printf(ACout, "Failed to access stream %s:%d\n", host, port); return 0; } consumeStream(ac); #ifdef _DEBUG_ACTUATOR_ mnstr_printf(ACout, "stream consumed\n"); #endif } if (mode == ACTIVE) do { err = socket_client_connect(&sockfd, host, port); if (err) { mnstr_printf(ACout, "actuator connect fails: %s\n", err); MT_sleep_ms(1000); } } while (err); if (mode == PASSIVE) { err = socket_server_listen(sockfd, &(ac->newsockfd)); if (err) { mnstr_printf(ACout, "ACTUATOR:server listen fails:%s\n", err); return 0; } } do { if (mode == PASSIVE) { #ifdef _DEBUG_ACTUATOR_ mnstr_printf(ACout, "Actuator listens\n"); #endif if (protocol == UDP) ac->fromServer = udp_rastream(host, port, actuator); else ac->fromServer = socket_rastream(ac->newsockfd, actuator); if (ac->fromServer == NULL) { perror("Actuator: Could not open stream"); mnstr_printf(ACout, "stream %s.%d.%s\n", host, port, actuator); return 0; } consumeStream(ac); } else if (mode == ACTIVE) { #ifdef _DEBUG_ACTUATOR_ mnstr_printf(ACout, "Actuator connects\n"); #endif err = socket_client_connect(&(ac->newsockfd), host, port); if (err) { mnstr_printf(ACout, "ACTUATOR:start client:%s\n", err); continue; } #ifdef _DEBUG_ACTUATOR_ mnstr_printf(ACout, "Initialize stream\n"); #endif if (protocol == UDP) ac->fromServer = udp_rastream(host, port, actuator); else ac->fromServer = socket_rastream(ac->newsockfd, actuator); if (ac->fromServer == NULL) { perror("Actuator: Could not open stream"); mnstr_printf(ACout, "stream %s.%d.%s\n", host, port, actuator); continue; } } consumeStream(ac); } while (mode == PASSIVE && (events == -1 || tuples < events)); socket_close(sockfd); terminate(ac); return 0; }