/* * libmaitretarot. * Copyright (C) 2002 Yves Mettier * Code taken from the MyAM project, also (c) Yves Mettier * 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; either version 2 of the License, or (at your option) * any later version. * 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. */ /* * HOW DOES NET_CONSUMER WORK? * * First, init gthreads with g_thread_init(NULL); * * Second, init net_consumer with: * channels_set = libmt_channels_set_new(sock_id); * where sock_id is the socket identifier from which the data are read. * * Then, except for the channel 0 (enabled by default), enable * the channels you want to read with: * libmt_channels_set_enable(channels_set,channel_id); * where channels_set is what libmt_channels_set_new returned * and where channel_id is the channel identifier. * * To read/write data on a channel: * libmt_channels_set_read(channels_set, channel_id, buffer, len); * libmt_channels_set_write(channels_set, channel_id, buffer, len); * where channels_set is what libmt_channels_set_new returned * and where channel_id is the channel identifier * and where buffer is a char* buffer where the data will be read/written * and where len is the max length of data to put in the buffer. * * To free the channels_set: * libmt_channels_set_free(channels_set); * * Misc functions: * libmt_channels_set_is_socket_working(channels_set); * returns TRUE if the socket is working (not closed) and FALSE otherwise * * libmt_channels_set_has_enough_data_to_read(channels_set, channel_id,size); * returns if there is enough to read on the channel channel_id. */ #include #include #include #include #include #include #include #include #include #include #include #include "net.h" #include "net_consumer.h" #include "maitretarot.h" gchar *libmt_buffer = NULL; gint libmt_buf_len = 0; static GMutex *channel_data_rw_mutex = NULL; int channel_get_index_from_id (libmt_channels_set_t * c, int channel_id) { int i; for (i = 0; c->channel[i]; i++) { if (c->channel[i]->id == channel_id) return (i); } return (-1); } int channel_init_channel (libmt_channels_set_t * c, int channel_id) { int l; g_assert (c); if (!c->channel) { c->channel = g_malloc0 (2 * sizeof (libmt_channel_t *)); c->channel[0] = g_malloc0 (sizeof (libmt_channel_t)); c->channel[0]->buffer = g_malloc0 (DEFAULT_BUFFER_LENGTH * sizeof (gchar)); c->channel[0]->data_r = 0; c->channel[0]->data_w = 0; c->channel[0]->buf_len = DEFAULT_BUFFER_LENGTH; c->channel[0]->id = 0; c->channel[0]->enabled = TRUE; c->channel[0]->an_error_occured = FALSE; } if ((l = channel_get_index_from_id (c, channel_id)) < 0) { for (l = 0; c->channel[l]; l++); c->channel = g_realloc (c->channel[l]->buffer, (2 + l) * sizeof (libmt_channel_t *)); c->channel[l + 1] = NULL; c->channel[l] = g_malloc0 (sizeof (libmt_channel_t)); c->channel[l]->buffer = g_malloc0 (DEFAULT_BUFFER_LENGTH * sizeof (gchar)); c->channel[l]->data_r = 0; c->channel[l]->data_w = 0; c->channel[l]->buf_len = DEFAULT_BUFFER_LENGTH; c->channel[l]->id = channel_id; c->channel[l]->enabled = FALSE; c->channel[l]->an_error_occured = FALSE; } return (l); } void channel_resize (libmt_channels_set_t * c, int channel_index, int len) { int l; l = ((len / DEFAULT_BUFFER_LENGTH) + 2) * DEFAULT_BUFFER_LENGTH; c->channel[channel_index]->buffer = g_realloc (c->channel[channel_index]->buffer, l * sizeof (gchar)); if (c->channel[channel_index]->data_w < c->channel[channel_index]->data_r) { int i; for (i = 0; i < c->channel[channel_index]->data_w; i++) { c->channel[channel_index]->buffer[c->channel[channel_index]-> buf_len + i] = c->channel[channel_index]->buffer[i]; } c->channel[channel_index]->data_w += c->channel[channel_index]->buf_len; } c->channel[channel_index]->buf_len = l; } void channel_add_data (libmt_channels_set_t * c, int channel_id, void *buffer, size_t len) { gint index; gint i; gchar *b; gint available_length; index = channel_init_channel (c, channel_id); b = buffer; available_length = (c->channel[index]->buf_len + c->channel[index]->data_r - c->channel[index]->data_w) % c->channel[index]->buf_len; if (len > available_length) channel_resize (c, index, len); for (i = 0; i < len; i++) { c->channel[index]->buffer[c->channel[index]->data_w++] = b[i]; if (c->channel[index]->data_w >= c->channel[index]->buf_len) c->channel[index]->data_w = 0; } } void channel_read_data_from_the_net (libmt_channels_set_t * c) { gint channel_id; gint len; gint i; gint index; g_mutex_lock (channel_data_rw_mutex); i = libmt_read (c->sock_id, &channel_id, sizeof (gint)); if (i != sizeof (gint)) { for (i = 0; c->channel[i]; i++) c->channel[i]->an_error_occured = TRUE; g_mutex_unlock (channel_data_rw_mutex); return; } index = channel_get_index_from_id (c, channel_id); i = libmt_read (c->sock_id, &len, sizeof (gint)); if (i != sizeof (gint)) { c->channel[index]->an_error_occured = TRUE; g_mutex_unlock (channel_data_rw_mutex); return; } if (len > libmt_buf_len) { libmt_buf_len = DEFAULT_BUFFER_LENGTH * (1 + len / DEFAULT_BUFFER_LENGTH); libmt_buffer = realloc (libmt_buffer, libmt_buf_len); } i = libmt_read (c->sock_id, libmt_buffer, len); if (i != len) { c->channel[index]->an_error_occured = TRUE; } if ((i > 0) && (index >= 0) && c->channel[index]->enabled) channel_add_data (c, channel_id, libmt_buffer, len); g_mutex_unlock (channel_data_rw_mutex); } ssize_t libmt_channels_set_read (libmt_channels_set_t * c, gint channel_id, void *buffer, size_t len) { gint index; int i; gchar *b; g_mutex_lock (channel_data_rw_mutex); index = channel_init_channel (c, channel_id); b = buffer; for (i = 0; i < len; i++) { if (c->channel[index]->data_r == c->channel[index]->data_w) break; b[i] = c->channel[index]->buffer[c->channel[index]->data_r++]; if (c->channel[index]->data_r >= c->channel[index]->buf_len) c->channel[index]->data_r = 0; } g_mutex_unlock (channel_data_rw_mutex); if ((i != len) && c->channel[index]->an_error_occured) return (-1); return (i); } ssize_t libmt_channels_set_write (libmt_channels_set_t * c, gint channel_id, void *buffer, size_t len) { ssize_t r; gint len1 = len; g_mutex_lock (channel_data_rw_mutex); if (libmt_write_data (c->sock_id, &channel_id, sizeof (gint)) != sizeof (gint)) { g_mutex_unlock (channel_data_rw_mutex); return (-1); } if (libmt_write_data (c->sock_id, &len1, sizeof (gint)) != sizeof (gint)) { g_mutex_unlock (channel_data_rw_mutex); return (-1); } r = libmt_write_data (c->sock_id, buffer, len); g_mutex_unlock (channel_data_rw_mutex); return (r); } gint libmt_channels_set_has_enough_data_to_read (libmt_channels_set_t * c, gint channel_id, gint size) { gint index = channel_init_channel (c, channel_id); gint r; g_mutex_lock (channel_data_rw_mutex); if (index < 0) { g_mutex_unlock (channel_data_rw_mutex); return (-1); } r = (c->channel[index]->buf_len + c->channel[index]->data_w - c->channel[index]->data_r) % c->channel[index]->buf_len; g_mutex_unlock (channel_data_rw_mutex); if (r >= size) return (1); if (c->channel[index]->an_error_occured) { return (-1); } return (0); } gboolean libmt_channels_set_channel_has_error (libmt_channels_set_t * c, gint channel_id) { gint index = channel_init_channel (c, channel_id); return (c->channel[index]->an_error_occured); } gpointer channels_loop (gpointer d) { libmt_channels_set_t *c = d; c->active = TRUE; while (1) { int r; fd_set rfds; struct timeval tv; tv.tv_sec = 1; tv.tv_usec = 0; FD_ZERO (&rfds); FD_SET (c->sock_id, &rfds); r = select (c->sock_id + 1, &rfds, NULL, NULL, &tv); if (r > 0) { channel_read_data_from_the_net (c); } else if (r < 0) { if (errno != EINTR) { c->active = FALSE; return (NULL); } } } } void libmt_channels_set_enable_channel (libmt_channels_set_t * c, int channel_id, gboolean enable) { gint index; g_mutex_lock (channel_data_rw_mutex); index = channel_init_channel (c, channel_id); g_assert (index >= 0); c->channel[index]->enabled = enable; g_mutex_unlock (channel_data_rw_mutex); } libmt_channels_set_t * libmt_channels_set_new (int sock_id) { libmt_channels_set_t *c = g_malloc (sizeof (libmt_channels_set_t)); c->sock_id = sock_id; c->channel = NULL; //g_assert (channel_data_rw_mutex == NULL); if (!channel_data_rw_mutex) channel_data_rw_mutex = g_mutex_new (); channel_init_channel (c, 0); c->thread_id = g_thread_create (channels_loop, c, FALSE, NULL); if (c->thread_id) return (c); g_free (c); return (NULL); } void libmt_channels_set_free (libmt_channels_set_t * c) { int i; if (c == NULL) return; for (i = 0; c->channel[i]; i++) { if (c->channel[i]->buffer != NULL) g_free (c->channel[i]->buffer); g_free (c->channel[i]); } g_free (c); } gboolean libmt_channels_set_is_socket_working (libmt_channels_set_t * c) { int r; fd_set rfds; struct timeval tv; if (!c->active) return (FALSE); tv.tv_sec = 0; tv.tv_usec = 1; FD_ZERO (&rfds); FD_SET (c->sock_id, &rfds); r = select (c->sock_id + 1, &rfds, NULL, NULL, &tv); if (r < 0) { if (errno != EINTR) { c->active = FALSE; return (FALSE); } } return (TRUE); } gint libmt_read_type (libmt_channels_set_t * channels_set, gint channel_id, libmt_net_data_type_t * type) { gint l; while ((l = libmt_channels_set_has_enough_data_to_read (channels_set, channel_id, sizeof (libmt_net_data_type_t)) == 0) ) usleep (100); if (l == -1) return (-1); l = libmt_channels_set_read (channels_set, channel_id, type, sizeof (libmt_net_data_type_t)); return (l == -1 ? -1 : 0); } gint libmt_write_type (libmt_channels_set_t * channels_set, gint channel_id, libmt_net_data_type_t * type) { return (libmt_channels_set_write (channels_set, channel_id, &type, sizeof (libmt_net_data_type_t)) == -1 ? -1 : 0); } gchar * libmtnetdata2string (libmt_net_data_type_e val) { switch (val) { case LIBMT_NET_DATA_TYPE_NO: return ("LIBMT_NET_DATA_TYPE_NO"); case LIBMT_NET_DATA_TYPE_GET_ID: return ("LIBMT_NET_DATA_TYPE_GET_ID"); case LIBMT_NET_DATA_TYPE_SEND_ID: return ("LIBMT_NET_DATA_TYPE_SEND_ID"); case LIBMT_NET_DATA_TYPE_SEND_PROTOCOL: return ("LIBMT_NET_DATA_TYPE_SEND_PROTOCOL"); case LIBMT_NET_DATA_TYPE_GET_PROTOCOL: return ("LIBMT_NET_DATA_TYPE_GET_PROTOCOL"); case LIBMT_NET_DATA_TYPE_SEND_PLACE: return ("LIBMT_NET_DATA_TYPE_SEND_PLACE"); case LIBMT_NET_DATA_TYPE_GET_NICK_LEN: return ("LIBMT_NET_DATA_TYPE_GET_NICK_LEN"); case LIBMT_NET_DATA_TYPE_GET_NICK: return ("LIBMT_NET_DATA_TYPE_GET_NICK"); case LIBMT_NET_DATA_TYPE_SEND_NICK_LEN: return ("LIBMT_NET_DATA_TYPE_SEND_NICK_LEN"); case LIBMT_NET_DATA_TYPE_SEND_NICKS: return ("LIBMT_NET_DATA_TYPE_SEND_NICKS"); case LIBMT_NET_DATA_TYPE_DILL_CARDS: return ("LIBMT_NET_DATA_TYPE_DILL_CARDS"); case LIBMT_NET_DATA_TYPE_SEND_BIDS: return ("LIBMT_NET_DATA_TYPE_SEND_BIDS"); case LIBMT_NET_DATA_TYPE_GET_BID: return ("LIBMT_NET_DATA_TYPE_GET_BID"); case LIBMT_NET_DATA_TYPE_SEND_FINAL_BIDS: return ("LIBMT_NET_DATA_TYPE_SEND_FINAL_BIDS"); case LIBMT_NET_DATA_TYPE_SHOW_CHIEN: return ("LIBMT_NET_DATA_TYPE_SHOW_CHIEN"); case LIBMT_NET_DATA_TYPE_SEND_ACK_FOR_CHIEN: return ("LIBMT_NET_DATA_TYPE_SEND_ACK_FOR_CHIEN"); case LIBMT_NET_DATA_TYPE_SEND_ACK_FOR_CARD: return ("LIBMT_NET_DATA_TYPE_SEND_ACK_FOR_CARD"); case LIBMT_NET_DATA_TYPE_GET_CHIEN: return ("LIBMT_NET_DATA_TYPE_GET_CHIEN"); case LIBMT_NET_DATA_TYPE_SEND_TURN_CARDS: return ("LIBMT_NET_DATA_TYPE_SEND_TURN_CARDS"); case LIBMT_NET_DATA_TYPE_GET_TURN_CARDS: return ("LIBMT_NET_DATA_TYPE_GET_TURN_CARDS"); case LIBMT_NET_DATA_TYPE_SEND_LAST_TURN_CARDS: return ("LIBMT_NET_DATA_TYPE_SEND_LAST_TURN_CARDS"); case LIBMT_NET_DATA_TYPE_SEND_SCORE: return ("LIBMT_NET_DATA_TYPE_SEND_SCORE"); case LIBMT_NET_DATA_TYPE_SEND_TURN_CARDS_QUESTION: return ("LIBMT_NET_DATA_TYPE_SEND_TURN_CARDS_QUESTION"); case LIBMT_NET_DATA_TYPE_ASK_BID_QUESTION: return ("LIBMT_NET_DATA_TYPE_ASK_BID_QUESTION"); case LIBMT_NET_DATA_TYPE_SHOW_CHIEN_AT_END: return ("LIBMT_NET_DATA_TYPE_SHOW_CHIEN_AT_END"); case LIBMT_NET_DATA_TYPE_ACK_REPLAY: return ("LIBMT_NET_DATA_TYPE_ACK_REPLAY"); case LIBMT_NET_DATA_TYPE_SEND_REPLAY_ANSWER: return ("LIBMT_NET_DATA_TYPE_SEND_REPLAY_ANSWER"); case LIBMT_NET_DATA_TYPE_END: return ("LIBMT_NET_DATA_TYPE_END"); } return ("undef"); } gboolean libmt_is_type_ok (libmt_net_data_type_t * type, libmt_net_data_type_t * expected_type, gboolean is_verbose) { if (type->type != expected_type->type) { if (is_verbose) g_printerr ("Got %s (%d,%d), expected %s (%d,%d)\n", libmtnetdata2string (type->type), type->type, type->value, libmtnetdata2string (expected_type->type), expected_type->type, expected_type->value); return (FALSE); } if (type->value != expected_type->value) { if (is_verbose) g_printerr ("Got %s (%d,%d), expected %s (%d,%d)\n", libmtnetdata2string (type->type), type->type, type->value, libmtnetdata2string (expected_type->type), expected_type->type, expected_type->value); return (FALSE); } return (TRUE); }