⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 mapi.c

📁 这个是内存数据库的客户端
💻 C
📖 第 1 页 / 共 5 页
字号:
	}	return strdup(errstr);}#endif /* HAVE_OPENSSL *//* (Re-)establish a connection with the server. */static MapiMsgconnect_to_server(Mapi mid){	struct sockaddr_in server;#ifdef HAVE_SYS_UN_H	struct sockaddr_un userver;#endif	struct sockaddr *serv;	socklen_t servsize;	SOCKET s;#ifdef HAVE_OPENSSL	SSL *ssl = NULL;#endif	if (mid->connected)		close_connection(mid);#ifdef HAVE_SYS_UN_H	if (#ifdef HAVE_OPENSSL		   !mid->secure &&#endif		   mid->hostname && mid->hostname[0] == '/') {		if (strlen(mid->hostname) >= sizeof(userver.sun_path)) {			return mapi_setError(mid, "path name too long", "mapi_reconnect", MERROR);		}		userver.sun_family = AF_UNIX;		strncpy(userver.sun_path, mid->hostname, sizeof(userver.sun_path));		serv = (struct sockaddr *) &userver;		servsize = sizeof(userver);	} else#endif	{		struct hostent *hp;		hp = gethostbyname(mid->hostname);		if (hp == NULL) {			return mapi_setError(mid, "gethostbyname failed", "mapi_reconnect", MERROR);		}		memset(&server, 0, sizeof(server));		memcpy(&server.sin_addr, hp->h_addr, hp->h_length);		server.sin_family = hp->h_addrtype;		server.sin_port = htons((unsigned short) (mid->port & 0xFFFF));		serv = (struct sockaddr *) &server;		servsize = sizeof(server);	}#ifdef HAVE_OPENSSL	if (mid->secure && mapi_ssl_ctx == NULL) {		mapi_ssl_ctx = SSL_CTX_new(SSLv23_method());		if (mapi_ssl_ctx == 0) {			char *errstr = ssl_error(SSL_ERROR_SSL, 0);			mapi_setError(mid, errstr, "mapi_reconnect", MERROR);			free(errstr);			return mid->error;		}		SSL_CTX_set_verify(mapi_ssl_ctx, SSL_VERIFY_NONE, NULL);	}#endif	s = socket(serv->sa_family, SOCK_STREAM, IPPROTO_TCP);	if (s < 0) {		return mapi_setError(mid, "Open socket failed", "mapi_reconnect", MERROR);	}	if (connect(s, serv, servsize) < 0) {#ifdef NATIVE_WIN32		fprintf(stderr, "!ERROR mapi_reconnect: connect: error %d\n", WSAGetLastError());#else		perror("!ERROR mapi_reconnect: connect");#endif		return mapi_setError(mid, "Setup connection failed", "mapi_reconnect", MERROR);	}#ifdef HAVE_OPENSSL	if (mid->secure) {		if ((ssl = SSL_new(mapi_ssl_ctx)) == 0) {			char *errstr = ssl_error(SSL_ERROR_SSL, 0);			mapi_setError(mid, errstr, "mapi_reconnect", MERROR);			free(errstr);			close(s);			return mid->error;		}		if (!SSL_set_fd(ssl, s)) {			char *errstr = ssl_error(SSL_ERROR_SSL, 0);			mapi_setError(mid, errstr, "mapi_reconnect", MERROR);			free(errstr);			SSL_free(ssl);			close(s);			return mid->error;		}		SSL_set_connect_state(ssl);		for (;;) {			int ret, err;			char *errstr;			ret = SSL_connect(ssl);			err = SSL_get_error(ssl, ret);			switch (err) {			case SSL_ERROR_WANT_READ:			case SSL_ERROR_WANT_WRITE:				/* try again */				continue;			case SSL_ERROR_NONE:				/* successful connect */				break;			case SSL_ERROR_WANT_CONNECT:			case SSL_ERROR_WANT_ACCEPT:			case SSL_ERROR_WANT_X509_LOOKUP:			default:				/* some error occurred */				SSL_free(ssl);				close(s);				errstr = ssl_error(err, ret);				mapi_setError(mid, errstr, "mapi_reconnect", MERROR);				free(errstr);				return mid->error;			}			break;		}		mid->to = ssl_wastream(ssl, "Mapi client write");		mid->from = ssl_rastream(ssl, "Mapi client read");	} else#endif	{		mid->to = socket_wastream(s, "Mapi client write");		mid->from = socket_rastream(s, "Mapi client read");	}	check_stream(mid, mid->to, "Cannot open socket for writing", "mapi_reconnect", mid->error);	check_stream(mid, mid->from, "Cannot open socket for reading", "mapi_reconnect", mid->error);	mid->connected = 1;	return MOK;}MapiMsgmapi_start_talking(Mapi mid){	char buf[BLOCK];	size_t len;	MapiHdl hdl;	int pversion = 0;	char *chal;	char *server;	char *protover;	char *rest;	mid->to = block_stream(mid->to);	check_stream(mid, mid->to, stream_error(mid->to), "mapi_start_talking", mid->error);	mid->from = block_stream(mid->from);	check_stream(mid, mid->from, stream_error(mid->from), "mapi_start_talking", mid->error);	/* consume server challenge */	len = stream_read_block(mid->from, buf, 1, BLOCK);	check_stream(mid, mid->from, "Connection terminated", "mapi_start_talking", (mid->blk.eos = 1, mid->error));	assert(len < BLOCK);	/* buf at this point looks like "challenge:servertype:protover[:.*]" */	chal = buf;	server = strchr(chal, ':');	if (server == NULL) {		mapi_setError(mid, "Challenge string is not valid", "mapi_start_talking", MERROR);		return mid->error;	}	*server++ = '\0';	protover = strchr(server, ':');	if (protover == NULL) {		mapi_setError(mid, "Challenge string is not valid", "mapi_start_talking", MERROR);		return mid->error;	}	*protover++ = '\0';	rest = strchr(protover, ':');	if (rest != NULL) {		*rest++ = '\0';	}	pversion = atoi(protover);	if (pversion < 8) {		/* because the headers changed, and because it makes no sense to		 * try and be backwards compatible, we bail out with a friendly		 * message saying so.		 */		snprintf(buf, BLOCK, "Unsupported protocol version: %d.  "				"This client only supports version 8 and up.  "				"Sorry, can't help you here!", pversion);		mapi_setError(mid, buf,	"mapi_start_talking", MERROR);		return mid->error;	} else if (pversion == 8) {		char* hash = NULL;		char* hashes = NULL;		/* the database has sent a list of supported hashes to us, it's		 * in the form of a comma separated list and in the variable		 * rest.  We try to use the strongest algorithm.		 */		hashes = rest;		hash = strchr(hashes, ':'); /* temp misuse hash */		if (hash) {			*hash = '\0';			rest = hash + 1;		}		hash = NULL;		/* TODO: make this actually obey the separation by commas, and		 * only allow full matches */		if (1 == 0) { /* language construct issue */#ifdef HAVE_OPENSSL		} else if (strstr(hashes, "SHA1") != NULL) {			/* The SHA-1 RSA hash algorithm is a 160 bit hash.  In order to			 * use in a string, a hexadecimal representation of the bit			 * sequence is used.			 */			unsigned char md[20]; /* should be SHA_DIGEST_LENGTH */			int n = strlen(mid->password) + strlen(chal);			char key[n];			strcpy(key, mid->password);			strncat(key, chal, strlen(chal));			SHA1((unsigned char*)key, n, md);			hash = malloc(sizeof(char) * (/*{SHA1}*/6 + 20 * 2 + 1));			sprintf(hash, "{SHA1}%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x"					"%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x",					md[0], md[1], md[2], md[3], md[4],					md[5], md[6], md[7], md[8], md[9],					md[10], md[11], md[12], md[13], md[14],					md[15], md[16], md[17], md[18], md[19]				);		} else if (strstr(hashes, "MD5") != NULL) {			/* The MD5 hash algorithm is a 128 bit hash.  In order to			 * use in a string, a hexadecimal representation of the bit			 * sequence is used.			 */			unsigned char md[16]; /* should be MD5_DIGEST_LENGTH */			int n = strlen(mid->password) + strlen(chal);			char key[n];			strcpy(key, mid->password);			strncat(key, chal, strlen(chal));			MD5((unsigned char*)key, n, md);			hash = malloc(sizeof(char) * (/*{MD5}*/5 + 16 * 2 + 1));			sprintf(hash, "{MD5}%02x%02x%02x%02x%02x%02x%02x%02x"					"%02x%02x%02x%02x%02x%02x%02x%02x",					md[0], md[1], md[2], md[3],					md[4], md[5], md[6], md[7],					md[8], md[9], md[10], md[11],					md[12], md[13], md[14], md[15]				);#endif#ifdef HAVE_CRYPT		} else if (strstr(hashes, "crypt") != NULL) {			/* The crypt hash algorithm uses UNIX crypt, a modification of			 * DES which uses a 2-char wide salt.  Because crypt only cares			 * about the first eight characters of the given password, the			 * challenge may not be taken into account at all.  As salt, the			 * last two characters of the challenge are used.			 */			char key[8]; /* NULL termination is not necessary */			char salt[3]; /* NULL termination is a necessity! */			char* cr;			int n;			/* prepare the key */			n = strlen(mid->password);			if (n >= 8) {				strncpy(key, mid->password, 8);			} else {				/* pad with the challenge, we know it is always 8+ chars */				strncpy(key, mid->password, n);				strncpy(key + n, chal, 8 - n);			}			/* prepare the salt */			n = strlen(chal);			salt[0] = chal[n - 2];			salt[1] = chal[n - 1];			salt[2] = '\0';			/* call crypt to do the work */			cr = crypt(key, salt);			assert (cr != NULL);			hash = malloc(sizeof(char) * (/*{crypt}*/7 + strlen(cr) + 1));			sprintf(hash, "{crypt}%s", cr);#endif		} else if (strstr(hashes, "plain") != NULL) {			/* The plain text algorithm, doesn't really hash at all.  It's			 * the easiest algorithm, as it just appends the challenge to			 * the password and returns it.			 */			hash = malloc(sizeof(char) * (/*{plain}*/7 +						strlen(mid->password) + strlen(chal) + 1));			sprintf(hash, "{plain}%s%s", mid->password, chal);		}		/* could use else here, but below looks cleaner */		if (hash == NULL) {			char *algo = strdup(rest);			/* the server doesn't support what we do (no plain?!?) */			snprintf(buf, BLOCK, "unsupported hash algorithms: %s", algo);			free(algo);			close_connection(mid);			return mapi_setError(mid, buf, "mapi_start_talking", MERROR);		}		/* in rest now should be the byte order of the server */		stream_set_byteorder(mid->from, strncmp(rest, "BIG", 3) == 0);				/* note: if we make the database field an empty string, it		 * means we want the default.  However, it *should* be there. */		snprintf(buf, BLOCK, "%s:%s:%s:%s:%s:\n",#ifdef WORDS_BIGENDIAN				"BIG",#else				"LIT",#endif				mid->username,				hash,				mid->language,				mid->database == NULL ? "" : mid->database);		free(hash);	}	if (mid->trace == MAPI_TRACE) {		printf("sending first request [%d]:%s", BLOCK, buf);		fflush(stdout);	}	len = strlen(buf);	stream_write(mid->to, buf, 1, len);	check_stream(mid, mid->to, "Could not send initial byte sequence", "mapi_start_talking", mid->error);	stream_flush(mid->to);	check_stream(mid, mid->to, "Could not send initial byte sequence", "mapi_start_talking", mid->error);	/* consume the welcome message from the server */	hdl = mapi_new_handle(mid);	mid->active = hdl;	read_into_cache(hdl, 0);	if (mid->error) {		if (hdl) {			/* propagate error from result to mid			   mapi_close_handle clears the errors, so			   save them first*/			char *errorstr = hdl->result ? hdl->result->errorstr : mid->errorstr;			MapiMsg error = mid->error;			if (hdl->result)				hdl->result->errorstr = NULL; /* clear these so errorstr doesn't get freed */			mid->errorstr = NULL;			mapi_close_handle(hdl);			mapi_setError(mid, errorstr, "mapi_start_talking", error);			free(errorstr);	/* now free it after a copy has been made */		}		return mid->error;	}	if (hdl->result && hdl->result->cache.line) {		int i;		size_t motdlen = 0;		struct MapiResultSet *result = hdl->result;		for (i = 0; i < result->cache.writer; i++) {			if (result->cache.line[i].rows) {				switch (result->cache.line[i].rows[0]) {					case '#':						motdlen += strlen(result->cache.line[i].rows) + 1;						break;					case '^': { /* FIXME: there may be multiple redirects */						char *tmp = result->cache.line[i].rows;						char *tmp2 = "";						/* redirect, looks like:						 * ^mapi:monetdb://localhost:50001/test?lang=sql&user=monetdb */						/* first see if we reached our redirection limit */						if (mid->redircnt > 10) {							mapi_close_handle(hdl);							mapi_setError(mid, "too many redirects", "mapi_start_talking", MERROR);							return(mid->error);						}						/* see if we can possibly handle the redirect */						tmp++;						if (strncmp("mapi:monetdb", tmp, 12) != 0) goto err;						/* parse components (we store the args						 * immediately in the mid... ok, that's dirty */						tmp += strlen("mapi:monetdb://");						mid->hostname = tmp;						if ((tmp = strchr(tmp, ':')) != NULL) {							*tmp++ = '\0';							tmp2 = tmp;						} else {							tmp = mid->hostname;						}						if ((tmp = strchr(tmp, '/')) != NULL) {							*tmp++ = '\0';							mid->port = atoi(tmp2);							if (mid->port == 0) goto err;							mid->database = tmp;						} else {							tmp = mid->hostname;							goto err;						}						if ((tmp = strchr(tmp, '?')) != NULL) {							char *tmp3;							*tmp++ = '\0';							tmp2 = tmp;							while ((tmp = strchr(tmp, '&')) != NULL) {								*tmp++ = '\0';								if ((tmp3 = strchr(tmp2, '=')) != NULL) {									*tmp3++ = '\0';									/* tmp2 = key, tmp3 = val */									if (strcmp("user", tmp2) == 0) {										free(mid->username);										mid->username = strdup(tmp3);									} else if (strcmp("lang", tmp2) == 0) {										free(mid->language);										mid->language = strdup(tmp3);									} else goto err;								} else goto err;								tmp2 = tmp;							}							tmp = tmp2;							if ((tmp3 = strchr(tmp2, '=')) != NULL) {								*tmp3++ = '\0';								/* tmp2 = key, tmp3 = val */								if (strcmp("user", tmp2) == 0) {									free(mid->username);									mid->username = strdup(tmp3);								} else if (strcmp("lang", tmp2) == 0) {									free(mid->language);									mid->language = strdup(tmp3);								} else goto err;							} else goto err;						} /* no optional arguments (weird) */						mid->redircnt++;						mapi_close_handle(hdl);						/* reconnect using the new values */						return(mapi_reconnect(mid));err:						tmp2 = alloca(sizeof(char) * (strlen(tmp) + 50));						sprintf(tmp2, "error while parsing redirect: %s", tmp);						mapi_close_handle(hdl);						mapi_setError(mid, tmp2, "mapi_start_talking", MERROR);						return(mid->error);					}				}			}		}		if (motdlen > 0) {			mid->motd = malloc(motdlen + 1);			*mid->motd = 0;			for (i = 0; i < result->cache.writer; i++)				if (result->cache.line[i].rows && result->cache.line[i].rows[0] == '#') {					strcat(mid->motd, result->cache.line[i].rows);					strcat(mid->motd, "\n");				}		}		mid->versionId = strcmp("Mserver 5.0", result->cache.line[0].rows) == 0 ? 5 : 4;	}	mapi_close_handle(hdl);	if (mid->trace == MAPI_TRACE)		printf("connection established\n");	if (mid->languageId == LANG_MAL)		return mid->error;	/* tell server about cachelimit */	mapi_cache_limit(mid, mid->cachelimit);	return mid->error;}MapiMsgmapi_reconnect(Mapi mid){	MapiMsg rc;	rc = connect_to_server(mid);	if (rc == MOK)		rc = mapi_start_talking(mid);	return rc;}/* Create a connection handle and connect to the server using the   specified parameters. */Mapimapi_connect(const char *host, int port, const char *username, const char *password, const char *lang, const char *dbname){	Mapi mid;	mid = mapi_mapi(host, port, username, password, lang, dbname);	if (mid && mid->error == MOK)		mapi_reconnect(mid);	/* actually, initial connect */	return mid;}/* Create a connection handle and connect to the server using the   specified parameters.  Use SSL (Secure Socket Layer) to encrypt all   data transfers with the server. */Mapimapi_connect_ssl(const char *host, int port, const char *username, const char *password, const char *lang, const char *dbname){	Mapi mid = mapi_mapi(host, port, username, password, lang, dbname);

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -