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

📄 nmconn.c

📁 Linux下的多协议即时通讯程序源代码
💻 C
字号:
/* * nmconn.c * * Copyright (c) 2004 Novell, Inc. All Rights Reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; version 2 of the License. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA	02111-1307	USA * */#include <glib.h>#include <unistd.h>#include <errno.h>#include <string.h>#include <ctype.h>#include <time.h>#include "nmconn.h"#ifdef _WIN32#include <windows.h>#endif#define NO_ESCAPE(ch) ((ch == 0x20) || (ch >= 0x30 && ch <= 0x39) || \					(ch >= 0x41 && ch <= 0x5a) || (ch >= 0x61 && ch <= 0x7a))/* Read data from conn until the end of a line */static NMERR_Tread_line(NMConn * conn, char *buff, int len){	NMERR_T rc = NM_OK;	int total_bytes = 0;	while ((rc == NM_OK) && (total_bytes < (len - 1))) {		rc = nm_read_all(conn, &buff[total_bytes], 1);		if (rc == NM_OK) {			total_bytes += 1;			if (buff[total_bytes - 1] == '\n') {				break;			}		}	}	buff[total_bytes] = '\0';	return rc;}static char *url_escape_string(char *src){	guint32 escape = 0;	char *p;	char *q;	char *encoded = NULL;	int ch;	static const char hex_table[16] = "0123456789abcdef";	if (src == NULL) {		return NULL;	}	/* Find number of chars to escape */	for (p = src; *p != '\0'; p++) {		ch = (guchar) *p;		if (!NO_ESCAPE(ch)) {			escape++;		}	}	encoded = g_malloc((p - src) + (escape * 2) + 1);	/* Escape the string */	for (p = src, q = encoded; *p != '\0'; p++) {		ch = (guchar) * p;		if (NO_ESCAPE(ch)) {			if (ch != 0x20) {				*q = ch;				q++;			} else {				*q = '+';				q++;			}		} else {			*q = '%';			q++;			*q = hex_table[ch >> 4];			q++;			*q = hex_table[ch & 15];			q++;		}	}	*q = '\0';	return encoded;}static char *encode_method(guint8 method){	char *str;	switch (method) {		case NMFIELD_METHOD_EQUAL:			str = "G";			break;		case NMFIELD_METHOD_UPDATE:			str = "F";			break;		case NMFIELD_METHOD_GTE:			str = "E";			break;		case NMFIELD_METHOD_LTE:			str = "D";			break;		case NMFIELD_METHOD_NE:			str = "C";			break;		case NMFIELD_METHOD_EXIST:			str = "B";			break;		case NMFIELD_METHOD_NOTEXIST:			str = "A";			break;		case NMFIELD_METHOD_SEARCH:			str = "9";			break;		case NMFIELD_METHOD_MATCHBEGIN:			str = "8";			break;		case NMFIELD_METHOD_MATCHEND:			str = "7";			break;		case NMFIELD_METHOD_NOT_ARRAY:			str = "6";			break;		case NMFIELD_METHOD_OR_ARRAY:			str = "5";			break;		case NMFIELD_METHOD_AND_ARRAY:			str = "4";			break;		case NMFIELD_METHOD_DELETE_ALL:			str = "3";			break;		case NMFIELD_METHOD_DELETE:			str = "2";			break;		case NMFIELD_METHOD_ADD:			str = "1";			break;		default:					/* NMFIELD_METHOD_VALID */			str = "0";			break;	}	return str;}NMConn *nm_create_conn(const char *addr, int port){	NMConn *conn = 	g_new0(NMConn, 1);	conn->addr = g_strdup(addr);	conn->port = port;	return conn;}void nm_release_conn(NMConn *conn){	if (conn) {		GSList *node;		for (node = conn->requests; node; node = node->next) {			if (node->data)				nm_release_request(node->data);		}		g_slist_free(conn->requests);		conn->requests = NULL;		if (conn->ssl_conn) {			g_free(conn->ssl_conn);			conn->ssl_conn = NULL;		}		g_free(conn->addr);		conn->addr = NULL;		g_free(conn);	}}intnm_tcp_write(NMConn * conn, const void *buff, int len){	if (conn == NULL || buff == NULL)		return -1;	if (!conn->use_ssl)		return (write(conn->fd, buff, len));	else if (conn->ssl_conn && conn->ssl_conn->write)		return (conn->ssl_conn->write(conn->ssl_conn->data, buff, len));	else		return -1;}intnm_tcp_read(NMConn * conn, void *buff, int len){	if (conn == NULL || buff == NULL)		return -1;	if (!conn->use_ssl)		return (read(conn->fd, buff, len));	else if (conn->ssl_conn && conn->ssl_conn->read)		return ((conn->ssl_conn->read)(conn->ssl_conn->data, buff, len));	else		return -1;}NMERR_Tnm_read_all(NMConn * conn, char *buff, int len){	NMERR_T rc = NM_OK;	int bytes_left = len;	int bytes_read;	int total_bytes = 0;	int retry = 1000;	if (conn == NULL || buff == NULL)		return NMERR_BAD_PARM;	/* Keep reading until buffer is full */	while (bytes_left) {		bytes_read = nm_tcp_read(conn, &buff[total_bytes], bytes_left);		if (bytes_read > 0) {			bytes_left -= bytes_read;			total_bytes += bytes_read;		} else {			if (errno == EAGAIN) {				if (--retry == 0) {					rc = NMERR_TCP_READ;					break;				}#ifdef _WIN32				Sleep(1);#else				usleep(1000);#endif			} else {				rc = NMERR_TCP_READ;				break;			}		}	}	return rc;}NMERR_Tnm_read_uint32(NMConn *conn, guint32 *val){	NMERR_T rc = NM_OK;	rc = nm_read_all(conn, (char *)val, sizeof(*val));	if (rc == NM_OK) {		*val = GUINT32_FROM_LE(*val);	}	return rc;}NMERR_Tnm_read_uint16(NMConn *conn, guint16 *val){	NMERR_T rc = NM_OK;	rc = nm_read_all(conn, (char *)val, sizeof(*val));	if (rc == NM_OK) {		*val = GUINT16_FROM_LE(*val);	}	return rc;}NMERR_Tnm_write_fields(NMConn * conn, NMField * fields){	NMERR_T rc = NM_OK;	NMField *field;	char *value = NULL;	char *method = NULL;	char buffer[4096];	int ret;	int bytes_to_send;	int val = 0;	if (conn == NULL || fields == NULL) {		return NMERR_BAD_PARM;	}	/* Format each field as valid "post" data and write it out */	for (field = fields; (rc == NM_OK) && (field->tag); field++) {		/* We don't currently handle binary types */		if (field->method == NMFIELD_METHOD_IGNORE ||			field->type == NMFIELD_TYPE_BINARY) {			continue;		}		/* Write the field tag */		bytes_to_send = g_snprintf(buffer, sizeof(buffer), "&tag=%s", field->tag);		ret = nm_tcp_write(conn, buffer, bytes_to_send);		if (ret < 0) {			rc = NMERR_TCP_WRITE;		}		/* Write the field method */		if (rc == NM_OK) {			method = encode_method(field->method);			bytes_to_send = g_snprintf(buffer, sizeof(buffer), "&cmd=%s", method);			ret = nm_tcp_write(conn, buffer, bytes_to_send);			if (ret < 0) {				rc = NMERR_TCP_WRITE;			}		}		/* Write the field value */		if (rc == NM_OK) {			switch (field->type) {				case NMFIELD_TYPE_UTF8:				case NMFIELD_TYPE_DN:					value = url_escape_string((char *) field->ptr_value);					bytes_to_send = g_snprintf(buffer, sizeof(buffer),											   "&val=%s", value);					if (bytes_to_send > (int)sizeof(buffer)) {						ret = nm_tcp_write(conn, buffer, sizeof(buffer));					} else {						ret = nm_tcp_write(conn, buffer, bytes_to_send);					}					if (ret < 0) {						rc = NMERR_TCP_WRITE;					}					g_free(value);					break;				case NMFIELD_TYPE_ARRAY:				case NMFIELD_TYPE_MV:					val = nm_count_fields((NMField *) field->ptr_value);					bytes_to_send = g_snprintf(buffer, sizeof(buffer),											   "&val=%u", val);					ret = nm_tcp_write(conn, buffer, bytes_to_send);					if (ret < 0) {						rc = NMERR_TCP_WRITE;					}					break;				default:					bytes_to_send = g_snprintf(buffer, sizeof(buffer),											   "&val=%u", field->value);					ret = nm_tcp_write(conn, buffer, bytes_to_send);					if (ret < 0) {						rc = NMERR_TCP_WRITE;					}					break;			}		}		/* Write the field type */		if (rc == NM_OK) {			bytes_to_send = g_snprintf(buffer, sizeof(buffer),									   "&type=%u", field->type);			ret = nm_tcp_write(conn, buffer, bytes_to_send);			if (ret < 0) {				rc = NMERR_TCP_WRITE;			}		}		/* If the field is a sub array then post its fields */		if (rc == NM_OK && val > 0) {			if (field->type == NMFIELD_TYPE_ARRAY ||				field->type == NMFIELD_TYPE_MV) {				rc = nm_write_fields(conn, (NMField *) field->ptr_value);			}		}	}	return rc;}NMERR_Tnm_send_request(NMConn *conn, char *cmd, NMField *fields,				nm_response_cb cb, gpointer data, NMRequest **request){	NMERR_T rc = NM_OK;	char buffer[512];	int bytes_to_send;	int ret;	NMField *request_fields = NULL;	char *str = NULL;	if (conn == NULL || cmd == NULL)		return NMERR_BAD_PARM;	/* Write the post */	bytes_to_send = g_snprintf(buffer, sizeof(buffer),							   "POST /%s HTTP/1.0\r\n", cmd);	ret = nm_tcp_write(conn, buffer, bytes_to_send);	if (ret < 0) {		rc = NMERR_TCP_WRITE;	}	/* Write headers */	if (rc == NM_OK) {		if (strcmp("login", cmd) == 0) {			bytes_to_send = g_snprintf(buffer, sizeof(buffer),									   "Host: %s:%d\r\n\r\n", conn->addr, conn->port);			ret = nm_tcp_write(conn, buffer, bytes_to_send);			if (ret < 0) {				rc = NMERR_TCP_WRITE;			}		} else {			bytes_to_send = g_snprintf(buffer, sizeof(buffer), "\r\n");			ret = nm_tcp_write(conn, buffer, bytes_to_send);			if (ret < 0) {				rc = NMERR_TCP_WRITE;			}		}	}	/* Add the transaction id to the request fields */	if (rc == NM_OK) {		if (fields)			request_fields = nm_copy_field_array(fields);		str = g_strdup_printf("%d", ++(conn->trans_id));		request_fields = nm_field_add_pointer(request_fields, NM_A_SZ_TRANSACTION_ID, 0,											  NMFIELD_METHOD_VALID, 0,											  str, NMFIELD_TYPE_UTF8);	}	/* Send the request to the server */	if (rc == NM_OK) {		rc = nm_write_fields(conn, request_fields);	}	/* Write the CRLF to terminate the data */	if (rc == NM_OK) {		ret = nm_tcp_write(conn, "\r\n", strlen("\r\n"));		if (ret < 0) {			rc = NMERR_TCP_WRITE;		}	}	/* Create a request struct, add it to our queue, and return it */	if (rc == NM_OK) {		NMRequest *new_request = nm_create_request(cmd, conn->trans_id,												   time(0), cb, NULL, data);		nm_conn_add_request_item(conn, new_request);		/* Set the out param if it was sent in, otherwise release the request */		if (request)			*request = new_request;		else			nm_release_request(new_request);	}	if (request_fields != NULL)		nm_free_fields(&request_fields);	return rc;}NMERR_Tnm_read_header(NMConn * conn){	NMERR_T rc = NM_OK;	char buffer[512];	char *ptr = NULL;	int i;	char rtn_buf[8];	int rtn_code = 0;	if (conn == NULL)		return NMERR_BAD_PARM;	*buffer = '\0';	rc = read_line(conn, buffer, sizeof(buffer));	if (rc == NM_OK) {		/* Find the return code */		ptr = strchr(buffer, ' ');		if (ptr != NULL) {			ptr++;			i = 0;			while (isdigit(*ptr) && (i < 3)) {				rtn_buf[i] = *ptr;				i++;				ptr++;			}			rtn_buf[i] = '\0';			if (i > 0)				rtn_code = atoi(rtn_buf);		}	}	/* Finish reading header, in the future we might want to do more processing here */	/* TODO: handle more general redirects in the future */	while ((rc == NM_OK) && (strcmp(buffer, "\r\n") != 0)) {		rc = read_line(conn, buffer, sizeof(buffer));	}	if (rc == NM_OK && rtn_code == 301)		rc = NMERR_SERVER_REDIRECT;	return rc;}NMERR_Tnm_read_fields(NMConn * conn, int count, NMField ** fields){	NMERR_T rc = NM_OK;	guint8 type;	guint8 method;	guint32 val;	char tag[64];	NMField *sub_fields = NULL;	char *str = NULL;	if (conn == NULL || fields == NULL)		return NMERR_BAD_PARM;	do {		if (count > 0) {			count--;		}		/* Read the field type, method, and tag */		rc = nm_read_all(conn, (char *)&type, sizeof(type));		if (rc != NM_OK || type == 0)			break;		rc = nm_read_all(conn, (char *)&method, sizeof(method));		if (rc != NM_OK)			break;		rc = nm_read_uint32(conn, &val);		if (rc != NM_OK)			break;		if (val > sizeof(tag)) {			rc = NMERR_PROTOCOL;			break;		}		rc = nm_read_all(conn, tag, val);		if (rc != NM_OK)			break;		if (type == NMFIELD_TYPE_MV || type == NMFIELD_TYPE_ARRAY) {			/* Read the subarray (first read the number of items in the array) */			rc = nm_read_uint32(conn, &val);			if (rc != NM_OK)				break;			if (val > 0) {				rc = nm_read_fields(conn, val, &sub_fields);				if (rc != NM_OK)					break;			}			*fields = nm_field_add_pointer(*fields, tag, 0, method,									   0, sub_fields, type);			sub_fields = NULL;		} else if (type == NMFIELD_TYPE_UTF8 || type == NMFIELD_TYPE_DN) {			/* Read the string (first read the length) */			rc = nm_read_uint32(conn, &val);			if (rc != NM_OK)				break;			if (val >= NMFIELD_MAX_STR_LENGTH) {				rc = NMERR_PROTOCOL;				break;			}			if (val > 0) {				str = g_new0(char, val + 1);				rc = nm_read_all(conn, str, val);				if (rc != NM_OK)					break;				*fields = nm_field_add_pointer(*fields, tag, 0, method,											   0, str, type);				str = NULL;			}		} else {			/* Read the numerical value */			rc = nm_read_uint32(conn, &val);			if (rc != NM_OK)				break;			*fields = nm_field_add_number(*fields, tag, 0, method,										  0, val, type);		}	} while ((type != 0) && (count != 0));	if (str != NULL) {		g_free(str);	}	if (sub_fields != NULL) {		nm_free_fields(&sub_fields);	}	return rc;}voidnm_conn_add_request_item(NMConn * conn, NMRequest * request){	if (conn == NULL || request == NULL)		return;	nm_request_add_ref(request);	conn->requests = g_slist_append(conn->requests, request);}voidnm_conn_remove_request_item(NMConn * conn, NMRequest * request){	if (conn == NULL || request == NULL)		return;	conn->requests = g_slist_remove(conn->requests, request);	nm_release_request(request);}NMRequest *nm_conn_find_request(NMConn * conn, int trans_id){	NMRequest *req = NULL;	GSList *itr = NULL;	if (conn == NULL)		return NULL;	itr = conn->requests;	while (itr) {		req = (NMRequest *) itr->data;		if (req != NULL && nm_request_get_trans_id(req) == trans_id) {			return req;		}		itr = g_slist_next(itr);	}	return NULL;}const char *nm_conn_get_addr(NMConn * conn){	if (conn == NULL)		return NULL;	else		return conn->addr;}intnm_conn_get_port(NMConn * conn){	if (conn == NULL)		return -1;	else		return conn->port;}

⌨️ 快捷键说明

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