diff options
| -rw-r--r-- | tests/gtcp_proxy/README.txt | 4 | ||||
| -rwxr-xr-x | tests/gtcp_proxy/gtcp-proxy | bin | 0 -> 25665 bytes | |||
| -rw-r--r-- | tests/gtcp_proxy/gtcp-proxy.c | 678 | ||||
| -rw-r--r-- | tests/gtcp_proxy/gtcp.c | 394 | ||||
| -rw-r--r-- | tests/gtcp_proxy/gtcp.h | 48 | 
5 files changed, 1124 insertions, 0 deletions
| diff --git a/tests/gtcp_proxy/README.txt b/tests/gtcp_proxy/README.txt new file mode 100644 index 00000000..41907e2e --- /dev/null +++ b/tests/gtcp_proxy/README.txt @@ -0,0 +1,4 @@ + +gtcp-proxy is a 'man in the middle' program to monitor data flowing between +two network connections. + diff --git a/tests/gtcp_proxy/gtcp-proxy b/tests/gtcp_proxy/gtcp-proxyBinary files differ new file mode 100755 index 00000000..6896b437 --- /dev/null +++ b/tests/gtcp_proxy/gtcp-proxy diff --git a/tests/gtcp_proxy/gtcp-proxy.c b/tests/gtcp_proxy/gtcp-proxy.c new file mode 100644 index 00000000..39555c76 --- /dev/null +++ b/tests/gtcp_proxy/gtcp-proxy.c @@ -0,0 +1,678 @@ +/** + * xrdp: A Remote Desktop Protocol server. + * + * Copyright (C) Laxmikant Rashinkar 2013 LK.Rashinkar@gmail.com + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + *     http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <stdio.h> +#include <gtk/gtk.h> +#include <pthread.h> + +#include "gtcp.h" + +#define WINDOW_TITLE    "Tcp Proxy Version 1.0" +#define CONTEXT_ID      1 +#define MSG_INFO        GTK_MESSAGE_INFO +#define MSG_WARN        GTK_MESSAGE_WARNING +#define MSG_ERROR       GTK_MESSAGE_ERROR +#define MAIN_THREAD_YES 0 +#define MAIN_THREAD_NO  1 + +/* globals */ +pthread_t g_tid; +int       g_keep_running   = 1; +int       g_loc_io_count   = 0;  /* bytes read from local port  */ +int       g_rem_io_count   = 0;  /* bytes read from remote port */ + +GtkWidget *g_btn_start; +GtkWidget *g_tbx_loc_port; +GtkWidget *g_tbx_rem_ip; +GtkWidget *g_tbx_rem_port; +GtkWidget *g_tbx_loc_stats; +GtkWidget *g_tbx_rem_stats; +GtkWidget *g_statusbar; +GtkWidget *g_txtvu_loc_port; +GtkWidget *g_txtvu_rem_port; + +/* forward declarations */ +static void *tcp_proxy(void *arg); + +static void show_msg(int not_main_thread, int style, +                     const gchar *title, const gchar *msg); + +static void show_status(int not_main_thread, char *msg); +static void clear_status(int not_main_thread); +static void enable_btn_start(int main_thread); +static void disable_btn_start(int main_thread); + +/* getters */ +static char *get_local_port(); +static char *get_remote_ip(); +static char *get_remote_port(); + +/* setters */ +static void show_loc_port_stats(int main_thread, int count); +static void show_rem_port_stats(int main_thread, int count); + +/* handlers */ +static gboolean on_delete_event(GtkWidget *widget, GdkEvent *ev, gpointer data); +static void on_destroy(GtkWidget *widget, gpointer data); +static void on_start_clicked(GtkWidget *widget, gpointer data); +static void on_clear_clicked(GtkWidget *widget, gpointer data); +static void on_quit_clicked(GtkWidget *widget, gpointer data); + +int main(int argc, char **argv) +{ +    /* init threads */ +    g_thread_init(NULL); +    gdk_threads_init(); + +    /* setup GTK */ +    gtk_init(&argc, &argv); + +    /* create labels and right justify them */ +    GtkWidget *lbl_loc_port    = gtk_label_new("Local port"); +    GtkWidget *lbl_rem_ip      = gtk_label_new("Remote IP"); +    GtkWidget *lbl_rem_port    = gtk_label_new("Remote port"); +    GtkWidget *lbl_loc_stats   = gtk_label_new("Local port recv stats"); +    GtkWidget *lbl_rem_stats   = gtk_label_new("Remote port recv stats"); + +    gtk_misc_set_alignment(GTK_MISC(lbl_loc_port), 1.0, 0.5); +    gtk_misc_set_alignment(GTK_MISC(lbl_rem_ip), 1.0, 0.5); +    gtk_misc_set_alignment(GTK_MISC(lbl_rem_port), 1.0, 0.5); +    gtk_misc_set_alignment(GTK_MISC(lbl_loc_stats), 1.0, 0.5); +    gtk_misc_set_alignment(GTK_MISC(lbl_rem_stats), 1.0, 0.5); + +    /* create text boxes */ +    g_tbx_loc_port   = gtk_entry_new(); +    g_tbx_rem_ip     = gtk_entry_new(); +    g_tbx_rem_port   = gtk_entry_new(); +    g_tbx_loc_stats  = gtk_entry_new(); +    g_tbx_rem_stats  = gtk_entry_new(); + +    /* stat text boxes are read only */ +    gtk_entry_set_editable(GTK_ENTRY(g_tbx_loc_stats), FALSE); +    gtk_entry_set_editable(GTK_ENTRY(g_tbx_rem_stats), FALSE); + +    /* enable when debugging */ +#if 0 +    gtk_entry_set_text(GTK_ENTRY(g_tbx_loc_port), "1234"); +    gtk_entry_set_text(GTK_ENTRY(g_tbx_rem_ip), "192.168.2.20"); +    gtk_entry_set_text(GTK_ENTRY(g_tbx_rem_port), "43222"); +#endif + +    /* setup buttons inside a HBox */ +    g_btn_start          = gtk_button_new_with_label("Start listening"); +    GtkWidget *btn_clear = gtk_button_new_with_label("Clear receive stats"); +    GtkWidget *btn_quit  = gtk_button_new_with_label("Quit application"); + +    GtkWidget *hbox = gtk_hbox_new(FALSE, 5); +    gtk_box_pack_start_defaults(GTK_BOX(hbox), g_btn_start); +    gtk_box_pack_start_defaults(GTK_BOX(hbox), btn_clear); +    gtk_box_pack_start_defaults(GTK_BOX(hbox), btn_quit); + +#if 0 +    g_txtvu_loc_port = gtk_text_view_new(); +    g_txtvu_rem_port = gtk_text_view_new(); +#endif + +    /* create table */ +    GtkWidget *table = gtk_table_new(8, 3, FALSE); + +    int row = 0; + +    /* insert labels into table */ +    gtk_table_attach(GTK_TABLE(table), lbl_loc_port, 0, 1, row, row + 1, +                     GTK_FILL, GTK_FILL, 5, 0); +    row++; + +    gtk_table_attach(GTK_TABLE(table), lbl_rem_ip, 0, 1, row, row + 1, +                     GTK_FILL, GTK_FILL, 5, 0); +    row++; + +    gtk_table_attach(GTK_TABLE(table), lbl_rem_port, 0, 1, row, row + 1, +                     GTK_FILL, GTK_FILL, 5, 0); +    row++; + +    gtk_table_attach(GTK_TABLE(table), lbl_loc_stats, 0, 1, row, row + 1, +                     GTK_FILL, GTK_FILL, 5, 0); +    row++; + +    gtk_table_attach(GTK_TABLE(table), lbl_rem_stats, 0, 1, row, row + 1, +                     GTK_FILL, GTK_FILL, 5, 0); +    row++; + +    row = 0; + +    /* insert text boxes into table */ +    gtk_table_attach(GTK_TABLE(table), g_tbx_loc_port, 1, 2, row, row + 1, +                     GTK_FILL, GTK_FILL, 5, 0); +    row++; + +    gtk_table_attach(GTK_TABLE(table), g_tbx_rem_ip, 1, 2, row, row + 1, +                     GTK_FILL, GTK_FILL, 5, 0); +    row++; + +    gtk_table_attach(GTK_TABLE(table), g_tbx_rem_port, 1, 2, row, row + 1, +                     GTK_FILL, GTK_FILL, 5, 0); +    row++; + +    gtk_table_attach(GTK_TABLE(table), g_tbx_loc_stats, 1, 2, row, row + 1, +                     GTK_FILL, GTK_FILL, 5, 0); +    row++; + +    gtk_table_attach(GTK_TABLE(table), g_tbx_rem_stats, 1, 2, row, row + 1, +                     GTK_FILL, GTK_FILL, 5, 0); +    row++; +    row++; + +    /* insert hbox with buttons into table */ +    gtk_table_attach(GTK_TABLE(table), hbox, 1, 2, row, row + 1, +                     GTK_FILL, GTK_FILL, 5, 0); +    row++; + +#if 0 +    /* text view to display hexdumps */ +    gtk_table_attach(GTK_TABLE(table), g_txtvu_loc_port, 0, 2, row, row + 1, +                     GTK_FILL, GTK_FILL, 5, 0); +    row++; +#endif + +    /* status bar to display messages */ +    g_statusbar = gtk_statusbar_new(); +    gtk_statusbar_set_has_resize_grip(GTK_STATUSBAR(g_statusbar), TRUE); +    gtk_table_attach(GTK_TABLE(table), g_statusbar, 0, 2, row, row + 1, +                     GTK_FILL, GTK_FILL, 5, 0); + +    /* setup main window */ +    GtkWidget *window = gtk_window_new(GTK_WINDOW_TOPLEVEL); +    gtk_container_set_border_width(GTK_CONTAINER(window), 5); +    gtk_window_set_default_size(GTK_WINDOW(window), 640, 480); +    gtk_window_set_title(GTK_WINDOW(window), WINDOW_TITLE); +    gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER); +    gtk_window_set_resizable(GTK_WINDOW(window), FALSE); + +    gtk_container_add(GTK_CONTAINER(window), table); +    gtk_widget_show_all(window); + +    /* setup callbacks */ +    g_signal_connect(window, "delete-event", G_CALLBACK(on_delete_event), NULL); +    g_signal_connect(window, "destroy", G_CALLBACK(on_destroy), NULL); + +    g_signal_connect(g_btn_start, "clicked", G_CALLBACK(on_start_clicked), NULL); +    g_signal_connect(btn_clear, "clicked", G_CALLBACK(on_clear_clicked), NULL); +    g_signal_connect(btn_quit, "clicked", G_CALLBACK(on_quit_clicked), NULL); + +    gdk_threads_enter(); +    gtk_main(); +    gdk_threads_leave(); + +    return 0; +} + +/** + * Start listening on specifed local socket; when we get a connection, + * connect to specified remote server and transfer data between local + * and remote server + *****************************************************************************/ + +static void *tcp_proxy(void *arg) +{ +    char buf[1024 * 32]; + +    int lis_skt = -1; +    int acc_skt = -1; +    int con_skt = -1; +    int sel     = 0; +    int rv      = 0; +    int i       = 0; +    int count   = 0; +    int sent    = 0; + +    /* create listener socket */ +    if ((lis_skt = tcp_socket_create()) < 0) +    { +        show_msg(MAIN_THREAD_NO, MSG_ERROR, "Creating socket", +                 "\nOperation failed. System out of resources"); +        enable_btn_start(MAIN_THREAD_NO); +        return NULL; +    } + +    /* place it in non blocking mode */ +    tcp_set_non_blocking(lis_skt); + +    if ((rv = tcp_bind(lis_skt, get_local_port())) != 0) +    { +        show_msg(MAIN_THREAD_NO, MSG_ERROR, "Bind error", +                 "\nUnable to bind socket, cannot continue"); +        tcp_close(lis_skt); +        enable_btn_start(MAIN_THREAD_NO); +        return NULL; +    } + +    /* listen for incoming connection */ +    if (tcp_listen(lis_skt)) +    { +        show_msg(MAIN_THREAD_NO, MSG_ERROR, "Listen error", +                 "\nUnable to listen on socket, cannot continue"); +        tcp_close(lis_skt); +        enable_btn_start(MAIN_THREAD_NO); +        return NULL; +    } + +    show_status(MAIN_THREAD_NO, "Waiting for client connections"); + +    /* accept incoming connection */ +    while (g_keep_running) +    { +        acc_skt = tcp_accept(lis_skt); +        if (acc_skt > 0) +        { +            /* client connected */ +            show_status(MAIN_THREAD_NO, "Client connected"); +            tcp_close(lis_skt); +            lis_skt = -1; +            break; +        } +        if ((acc_skt < 0) && (tcp_last_error_would_block())) +        { +            /* no connection, try again */ +            usleep(250); +            continue; +        } +        else +        { +            tcp_close(lis_skt); +            lis_skt = -1; +            enable_btn_start(MAIN_THREAD_NO); +            return NULL; +        } +    } + +    /* we have a client connection, try connecting to server */ +    if ((con_skt = tcp_socket()) < 0) +    { +        show_msg(MAIN_THREAD_NO, MSG_ERROR, "Creating socket", +                 "\nOperation failed. System out of resources"); +        tcp_close(lis_skt); +        tcp_close(acc_skt); +        enable_btn_start(MAIN_THREAD_NO); +        return NULL; +    } + +    /* place it in non blocking mode */ +    tcp_set_non_blocking(con_skt); + +    rv = tcp_connect(con_skt, get_remote_ip(), get_remote_port()); +#if 0 +    if (rv < 0) +    { +        show_status(MAIN_THREAD_NO, "Could not connect to server"); +        tcp_close(lis_skt); +        tcp_close(acc_skt); +        enable_btn_start(MAIN_THREAD_NO); +        return NULL; +    } +#endif + +    if ((rv < 0) && (tcp_last_error_would_block(con_skt))) +    { +        for (i = 0; i < 100; i++) +        { +            if (tcp_can_send(con_skt, 100)) +                break; + +            usleep(100); +        } + +        if (i == 100) +        { +            show_status(MAIN_THREAD_NO, "Could not connect to server"); +            tcp_close(lis_skt); +            tcp_close(acc_skt); +            enable_btn_start(MAIN_THREAD_NO); +            return NULL; +        } +    } + +    show_status(MAIN_THREAD_NO, "Connected to server"); +    rv = 0; + +    while (g_keep_running && rv == 0) +    { +        if ((sel = tcp_select(con_skt, acc_skt)) == 0) +        { +            usleep(10); +            continue; +        } + +        if (sel & 1) +        { +            /* can read from con_skt without blocking */ +            count = tcp_recv(con_skt, buf, 1024 * 16, 0); +            rv = count < 1; + +            if (rv == 0) +            { +                g_loc_io_count += count; +                show_loc_port_stats(MAIN_THREAD_NO, g_loc_io_count); + +                /* TODO: hexdump data here */ + +                sent = 0; + +                while ((sent < count) && (rv == 0) && (g_keep_running)) +                { +                    i = tcp_send(acc_skt, buf + sent, count - sent, 0); + +                    if ((i == -1) && tcp_last_error_would_block(acc_skt)) +                    { +                        tcp_can_send(acc_skt, 1000); +                    } +                    else if (i < 1) +                    { +                        rv = 1; +                    } +                    else +                    { +                        sent += i; +                    } +                } +            } +        } + +        if (sel & 2) +        { +            /* can read from acc_skt without blocking */ +            count = tcp_recv(acc_skt, buf, 1024 * 16, 0); +            rv = count < 1; + +            if (rv == 0) +            { +                g_rem_io_count += count; +                show_rem_port_stats(MAIN_THREAD_NO, g_rem_io_count); + +                /* TODO: hexdump data here */ + +                sent = 0; + +                while ((sent < count) && (rv == 0) && (g_keep_running)) +                { +                    i = tcp_send(con_skt, buf + sent, count - sent, 0); + +                    if ((i == -1) && tcp_last_error_would_block(con_skt)) +                    { +                        tcp_can_send(con_skt, 1000); +                    } +                    else if (i < 1) +                    { +                        rv = 1; +                    } +                    else +                    { +                        sent += i; +                    } +                } +            } +        } +    } + +    tcp_close(lis_skt); +    tcp_close(con_skt); +    tcp_close(acc_skt); + +    show_status(MAIN_THREAD_NO, "Connection closed"); +    enable_btn_start(MAIN_THREAD_NO); +    return NULL; +} + +/** + * Display a message using specified style dialog + * + * @param  style  information, warning or error + * @param  title  text to be displayed in title bar + * @param  msg    message to be displayed + *****************************************************************************/ + +static void show_msg(int not_main_window, int style, +                     const gchar *title, const gchar *msg) +{ +    GtkWidget *dialog; + +    if (not_main_window) +        gdk_threads_enter(); + +    dialog = gtk_message_dialog_new(GTK_WINDOW(NULL), +                                    GTK_DIALOG_DESTROY_WITH_PARENT, +                                    style, +                                    GTK_BUTTONS_OK, +                                    "%s", msg); + +    gtk_window_set_title(GTK_WINDOW(dialog), title); +    gtk_dialog_run(GTK_DIALOG(dialog)); +    gtk_widget_destroy(dialog); + +    if (not_main_window) +        gdk_threads_leave(); +} + +/** + * Write message to status bar + *****************************************************************************/ + +static void show_status(int not_main_thread, char *msg) +{ +    if (not_main_thread) +        gdk_threads_enter(); + +    gtk_statusbar_push(GTK_STATUSBAR(g_statusbar), CONTEXT_ID, msg); + +    if (not_main_thread) +        gdk_threads_leave(); +} + +/** + * Clear status bar + *****************************************************************************/ + +static void clear_status(int not_main_thread) +{ +    if (not_main_thread) +        gdk_threads_enter(); + +    gtk_statusbar_remove_all(GTK_STATUSBAR(g_statusbar), CONTEXT_ID); + +    if (not_main_thread) +        gdk_threads_leave(); +} + +/** + * Enable 'Start Listening' button + *****************************************************************************/ + +static void enable_btn_start(int not_main_thread) +{ +    if (not_main_thread) +        gdk_threads_enter(); + +    gtk_widget_set_sensitive(GTK_WIDGET(g_btn_start), TRUE); + +    if (not_main_thread) +        gdk_threads_leave(); +} + +/** + * Disable 'Start Listening' button + *****************************************************************************/ + +static void disable_btn_start(int not_main_thread) +{ +    if (not_main_thread) +        gdk_threads_enter(); + +    gtk_widget_set_sensitive(GTK_WIDGET(g_btn_start), FALSE); + +    if (not_main_thread) +        gdk_threads_leave(); +} + +/** + * Return local port setting + *****************************************************************************/ + +static char *get_local_port() +{ +    const char *cptr = gtk_entry_get_text(GTK_ENTRY(g_tbx_loc_port)); +    return (char *) cptr; +} + +/** + * Return remote IP setting + *****************************************************************************/ + +static char *get_remote_ip() +{ +    const char *cptr = gtk_entry_get_text(GTK_ENTRY(g_tbx_rem_ip)); +    return (char *) cptr; +} + +/** + * Return remote port setting + *****************************************************************************/ + +static char *get_remote_port() +{ +    const char *cptr = gtk_entry_get_text(GTK_ENTRY(g_tbx_rem_port)); +    return (char *) cptr; +} + +/** + * Update local port stat counter + *****************************************************************************/ + +static void show_loc_port_stats(int not_main_thread, int count) +{ +    char buf[128]; + +    sprintf(buf, "%d", count); + +    if (not_main_thread) +        gdk_threads_enter(); + +    gtk_entry_set_text(GTK_ENTRY(g_tbx_loc_stats), buf); + +    if (not_main_thread) +        gdk_threads_leave(); +} + +/** + * Update remote port stat counter + *****************************************************************************/ + +static void show_rem_port_stats(int not_main_thread, int count) +{ +    char buf[128]; + +    sprintf(buf, "%d", count); + +    if (not_main_thread) +        gdk_threads_enter(); + +    gtk_entry_set_text(GTK_ENTRY(g_tbx_rem_stats), buf); + +    if (not_main_thread) +        gdk_threads_leave(); +} + +/** + * User clicked on window close button + *****************************************************************************/ + +static gboolean on_delete_event(GtkWidget *widget, GdkEvent *ev, gpointer data) +{ +    return FALSE; +} + +/** + * Close application + *****************************************************************************/ + +static void on_destroy(GtkWidget *widget, gpointer data) +{ +    /* this will destory all windows and return control to gtk_main() */ +    gtk_main_quit(); +} + +/** + * Start a thread that listens for incoming connections + *****************************************************************************/ + +static void on_start_clicked(GtkWidget *widget, gpointer data) +{ +    /* local port must be specified */ +    if (gtk_entry_get_text_length(GTK_ENTRY(g_tbx_loc_port)) == 0) +    { +        show_msg(MAIN_THREAD_YES, MSG_ERROR, "Invalid entry", +                 "\nYou must enter a value for Local Port"); +        return; +    } + +    /* remote IP must be specified */ +    if (gtk_entry_get_text_length(GTK_ENTRY(g_tbx_rem_ip)) == 0) +    { +        show_msg(MAIN_THREAD_YES, MSG_ERROR, "Invalid entry", +                 "\nYou must enter a value for Remote IP"); +        return; +    } + +    /* remote port must be specified */ +    if (gtk_entry_get_text_length(GTK_ENTRY(g_tbx_rem_port)) == 0) +    { +        show_msg(MAIN_THREAD_YES, MSG_ERROR, "Invalid entry", +                 "\nYou must enter a value for Remote Port"); +        return; +    } + +    if (pthread_create(&g_tid, NULL, tcp_proxy, NULL)) +    { +        show_msg(MAIN_THREAD_YES, MSG_ERROR, "Starting listener", +                 "\nThread create error. System out of resources"); +        return; +    } + +    disable_btn_start(MAIN_THREAD_YES); +} + +/** + * Clear stat counters + *****************************************************************************/ + +static void on_clear_clicked(GtkWidget *widget, gpointer data) +{ +    g_loc_io_count = 0; +    g_rem_io_count = 0; +    show_loc_port_stats(MAIN_THREAD_YES, g_loc_io_count); +    show_rem_port_stats(MAIN_THREAD_YES, g_rem_io_count); +} + +/** + * Quit application + *****************************************************************************/ + +static void on_quit_clicked(GtkWidget *widget, gpointer data) +{ +    /* this will destory all windows and return control to gtk_main() */ +    gtk_main_quit(); +} diff --git a/tests/gtcp_proxy/gtcp.c b/tests/gtcp_proxy/gtcp.c new file mode 100644 index 00000000..9f0fcf88 --- /dev/null +++ b/tests/gtcp_proxy/gtcp.c @@ -0,0 +1,394 @@ +/** + * xrdp: A Remote Desktop Protocol server. + * + * Copyright (C) Jay Sorg 2013 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + *     http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "gtcp.h" + +/** + * Return a newly created socket or -1 on error + *****************************************************************************/ + +int tcp_socket_create(void) +{ +    int rv; +    int option_value; + +#if defined(_WIN32) +    int option_len; +#else +    unsigned int option_len; +#endif + +    /* in win32 a socket is an unsigned int, in linux, its an int */ +    if ((rv = (int) socket(PF_INET, SOCK_STREAM, 0)) < 0) +        return -1; + +    option_len = sizeof(option_value); + +    if (getsockopt(rv, SOL_SOCKET, SO_REUSEADDR, (char *) &option_value, +                   &option_len) == 0) +    { +        if (option_value == 0) +        { +            option_value = 1; +            option_len = sizeof(option_value); +            setsockopt(rv, SOL_SOCKET, SO_REUSEADDR, (char *) &option_value, +                       option_len); +        } +    } + +    option_len = sizeof(option_value); + +    if (getsockopt(rv, SOL_SOCKET, SO_SNDBUF, (char *) &option_value, +                   &option_len) == 0) +    { +        if (option_value < (1024 * 32)) +        { +            option_value = 1024 * 32; +            option_len = sizeof(option_value); +            setsockopt(rv, SOL_SOCKET, SO_SNDBUF, (char *) &option_value, +                       option_len); +        } +    } + +    return rv; +} + +/** + * Place specifed socket in non blocking mode + *****************************************************************************/ + +void tcp_set_non_blocking(int skt) +{ +    unsigned long i; + +#if defined(_WIN32) +    i = 1; +    ioctlsocket(skt, FIONBIO, &i); +#else +    i = fcntl(skt, F_GETFL); +    i = i | O_NONBLOCK; +    fcntl(skt, F_SETFL, i); +#endif +} + +/** + * Assign name to socket + * + * @param  skt  the socket to bind + * @param  port  the port to bind to + * + * @return 0 on success, -1 on error + *****************************************************************************/ + +int tcp_bind(int skt, char *port) +{ +    struct sockaddr_in s; + +    memset(&s, 0, sizeof(struct sockaddr_in)); +    s.sin_family = AF_INET; +    s.sin_port = htons((uint16_t) atoi(port)); +    s.sin_addr.s_addr = INADDR_ANY; + +    return bind(skt, (struct sockaddr *) &s, sizeof(struct sockaddr_in)); +} + +/** + * Listen for incoming connections + * + * @param  skt  the socket to listen on + * + * @return 0 on success, -1 on error + *****************************************************************************/ + +int tcp_listen(int skt) +{ +    return listen(skt, 2); +} + +/** + * Accept incoming connection + * + * @param  skt  socket to accept incoming connection on + * + * @return 0 on success, -1 on error + *****************************************************************************/ + +int tcp_accept(int skt) +{ +    int ret ; +    char ipAddr[256] ; +    struct sockaddr_in s; + +#if defined(_WIN32) +    int i; +#else +    unsigned int i; +#endif + +    i = sizeof(struct sockaddr_in); +    memset(&s, 0, i); +    return accept(skt, (struct sockaddr *)&s, &i); +} + +/** + * Check if the socket would block + * + * @return TRUE if would block, else FALSE + *****************************************************************************/ + +int tcp_last_error_would_block() +{ +#if defined(_WIN32) +    return WSAGetLastError() == WSAEWOULDBLOCK; +#else +    return (errno == EWOULDBLOCK) || (errno == EAGAIN) || (errno == EINPROGRESS); +#endif +} + +/** + * Close specified socket + *****************************************************************************/ + +void tcp_close(int skt) +{ +    if (skt <= 0) +        return; + +#if defined(_WIN32) +    closesocket(skt); +#else +    close(skt); +#endif +} + +/** + * Create a new socket + * + * @return new socket or -1 on error + *****************************************************************************/ + +int tcp_socket(void) +{ +    int rv; +    int option_value; + +#if defined(_WIN32) +    int option_len; +#else +    unsigned int option_len; +#endif + +    /* in win32 a socket is an unsigned int, in linux, its an int */ +    if ((rv = (int) socket(PF_INET, SOCK_STREAM, 0)) < 0) +        return -1; + +    option_len = sizeof(option_value); + +    if (getsockopt(rv, SOL_SOCKET, SO_REUSEADDR, (char *) &option_value, +                   &option_len) == 0) +    { +        if (option_value == 0) +        { +            option_value = 1; +            option_len = sizeof(option_value); +            setsockopt(rv, SOL_SOCKET, SO_REUSEADDR, (char *) &option_value, +                       option_len); +        } +    } + +    option_len = sizeof(option_value); + +    if (getsockopt(rv, SOL_SOCKET, SO_SNDBUF, (char *) &option_value, +                   &option_len) == 0) +    { +        if (option_value < (1024 * 32)) +        { +            option_value = 1024 * 32; +            option_len = sizeof(option_value); +            setsockopt(rv, SOL_SOCKET, SO_SNDBUF, (char *) &option_value, +                       option_len); +        } +    } + +    return rv; +} + +/** + * Connect to a server + * + * @param  skt      opaque socket obj + * @param  address  connect to this server + * @param  port     using this port + * + * @return 0 on success, -1 on error + *****************************************************************************/ + +int tcp_connect(int skt, const char *hostname, const char *port) +{ +    struct sockaddr_in  s; +    struct hostent     *h; + +    memset(&s, 0, sizeof(struct sockaddr_in)); +    s.sin_family = AF_INET; +    s.sin_port = htons((uint16_t) atoi(port)); +    s.sin_addr.s_addr = inet_addr(hostname); + +    if (s.sin_addr.s_addr == INADDR_NONE) +    { +        h = gethostbyname(hostname); + +        if (h != 0) +        { +            if (h->h_name != 0) +            { +                if (h->h_addr_list != 0) +                { +                    if ((*(h->h_addr_list)) != 0) +                    { +                        s.sin_addr.s_addr = *((int *)(*(h->h_addr_list))); +                    } +                } +            } +        } +    } + +    return connect(skt, (struct sockaddr *) &s, sizeof(struct sockaddr_in)); +} + +/** + * Return 1 if we can write to the socket, 0 otherwise + *****************************************************************************/ + +int tcp_can_send(int skt, int millis) +{ +    fd_set         wfds; +    struct timeval time; +    int            rv; + +    time.tv_sec = millis / 1000; +    time.tv_usec = (millis * 1000) % 1000000; +    FD_ZERO(&wfds); + +    if (skt > 0) +    { +        FD_SET(((unsigned int) skt), &wfds); +        rv = select(skt + 1, 0, &wfds, 0, &time); + +        if (rv > 0) +        { +            return tcp_socket_ok(skt); +        } +    } + +    return 0; +} + +/** + * Return 1 if socket is OK, 0 otherwise + *****************************************************************************/ + +int tcp_socket_ok(int skt) +{ +    int opt; + +#if defined(_WIN32) +    int opt_len; +#else +    unsigned int opt_len; +#endif + +    opt_len = sizeof(opt); + +    if (getsockopt(skt, SOL_SOCKET, SO_ERROR, (char *) (&opt), &opt_len) == 0) +    { +        if (opt == 0) +            return 1; +    } + +    return 0; +} + +/** + * Check if specified sockets can be operated on without blocking + * + * @return 1 if they can be operated on or 0 if blocking would occur + *****************************************************************************/ + +int tcp_select(int sck1, int sck2) +{ +    fd_set         rfds; +    struct timeval time; + +    int            max = 0; +    int            rv  = 0; + +    memset(&rfds, 0, sizeof(fd_set)); +    memset(&time, 0, sizeof(struct timeval)); + +    time.tv_sec = 0; +    time.tv_usec = 0; +    FD_ZERO(&rfds); + +    if (sck1 > 0) +        FD_SET(((unsigned int) sck1), &rfds); + +    if (sck2 > 0) +        FD_SET(((unsigned int) sck2), &rfds); + +    max = sck1; + +    if (sck2 > max) +        max = sck2; + +    rv = select(max + 1, &rfds, 0, 0, &time); + +    if (rv > 0) +    { +        rv = 0; + +        if (FD_ISSET(((unsigned int) sck1), &rfds)) +            rv = rv | 1; + +        if (FD_ISSET(((unsigned int)sck2), &rfds)) +            rv = rv | 2; +    } +    else +    { +        rv = 0; +    } + +    return rv; +} + +int tcp_recv(int skt, void *ptr, int len, int flags) +{ +#if defined(_WIN32) +    return recv(skt, (char *) ptr, len, flags); +#else +    return recv(skt, ptr, len, flags); +#endif +} + +int tcp_send(int skt, const void *ptr, int len, int flags) +{ +#if defined(_WIN32) +    return send(skt, (const char *)ptr, len, flags); +#else +    return send(skt, ptr, len, flags); +#endif +} diff --git a/tests/gtcp_proxy/gtcp.h b/tests/gtcp_proxy/gtcp.h new file mode 100644 index 00000000..970540ef --- /dev/null +++ b/tests/gtcp_proxy/gtcp.h @@ -0,0 +1,48 @@ +/** + * xrdp: A Remote Desktop Protocol server. + * + * Copyright (C) Jay Sorg 2013 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + *     http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef _GTCP_H +#define _GTCP_H + +#include <stdint.h> +#include <sys/types.h> +#include <sys/socket.h> +#include <errno.h> +#include <unistd.h> +#include <fcntl.h> +#include <string.h> +#include <netinet/in.h> +#include <netinet/tcp.h> +#include <netdb.h> + +int  tcp_socket_create(void); +void tcp_set_non_blocking(int skt); +int  tcp_bind(int skt, char *port); +int  tcp_listen(int skt); +int  tcp_accept(int skt); +int  tcp_last_error_would_block(); +void tcp_close(int skt); +int  tcp_socket(void); +int  tcp_connect(int skt, const char *hostname, const char *port); +int  tcp_can_send(int skt, int millis); +int  tcp_socket_ok(int skt); +int  tcp_select(int sck1, int sck2); +int  tcp_recv(int skt, void *ptr, int len, int flags); +int  tcp_send(int skt, const void *ptr, int len, int flags); + +#endif | 
