--- a/src/protocols/novell/nmconn.c Sat Aug 19 00:24:14 2006 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,701 +0,0 @@ -/* - * 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_T -read_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); - } -} - -int -nm_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; -} - -int -nm_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_T -nm_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 = 10; - - 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(1000); -#else - usleep(1000); -#endif - } else { - rc = NMERR_TCP_READ; - break; - } - } - } - return rc; -} - -NMERR_T -nm_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_T -nm_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_T -nm_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_T -nm_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_T -nm_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_T -nm_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; -} - -void -nm_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); -} - -void -nm_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; -} - -int -nm_conn_get_port(NMConn * conn) -{ - if (conn == NULL) - return -1; - else - return conn->port; -}