/* * message.c * * Code handling the transmission of text messages. This relies on transport.c * to do the actual moving. This is all allocation and deallocation of * data structures that the transport layer makes use of. * * Copyright (c) 2004 Todd MacDermid * */ #include #include #include #include #include #include #include #include /* * msg_info_init is responsible for allocating msg_transit_info * structures. These structures will be assigned to a channel * if successful. * * Returns a pointer to the new structure on success, NULL on failure. */ struct msg_transit_info * msg_info_init(cutlass_t *cut_handle, conn_t *conn, int direction) { struct msg_transit_info *new_message; if((NULL == cut_handle) || (NULL == conn)) { cutlass_sysmsg(cut_handle, CUT_ERROR, "msg_info_init: Passed a NULL pointer\n"); return(NULL); } new_message = calloc(1, sizeof(struct msg_transit_info)); if(new_message == NULL) { cutlass_sysmsg(cut_handle, CUT_ERROR, "msg_info_init: Error allocating memory\n"); return(NULL); } return(new_message); } /* * msg_info_destroy is responsible for safely deallocating the * msg_transit_info structure and any substructures or descriptors * associated with it. Returns nothing. (What would you do if * it failed?) */ void msg_info_destroy(cutlass_t *cut_handle, struct msg_transit_info *msg_info) { if((NULL == cut_handle) || (NULL == msg_info)) { cutlass_sysmsg(cut_handle, CUT_ERROR, "msg_info_destroy: Passed a NULL pointer\n"); return; } free(msg_info); } /* * cutlass_msg_send is what gets called to actually transmit a text * message to a remote connection, via the transport system. This * is part of the externally exposed API. It is also called by * the msg_groupcast and msg_broadcast functions. * * returns the channel_id on success, and -1 on error. */ int cutlass_msg_send(cutlass_t *cut_handle, uint8_t *fingerprint, uint8_t *message) { struct msg_transit_info *msg_node; struct channel *transport_info; struct timespec now; conn_t *conn; int msg_len; uint8_t new_channel; if((NULL == cut_handle) || (NULL == fingerprint) || (NULL == message)) { cutlass_sysmsg(cut_handle, CUT_ERROR, "cutlass_msg_send: Passed a NULL pointer\n"); return(-1); } msg_len = strlen(message); if(msg_len > (CUT_MSG_LEN_MAX-1)) { cutlass_sysmsg(cut_handle, CUT_ERROR, "cutlass_msg_send: message too long\n"); return(-1); } conn = hashtable_fingerprint_find(cut_handle, fingerprint); if(NULL == conn) { cutlass_sysmsg(cut_handle, CUT_DEBUG, "cutlass_msg_send: Couldn't find connection\n"); return(-1); } msg_node = msg_info_init(cut_handle, conn, CUT_OUT); if(msg_node == NULL) { cutlass_sysmsg(cut_handle, CUT_ERROR, "cutlass_msg_send: Could not enqueue message\n"); pthread_mutex_unlock(&(conn->conn_mutex)); return(-1); } if(CUTSTATE_ACTIVE != conn->conn_state) { cutlass_sysmsg(cut_handle, CUT_INFO, "cutlass_msg_send: " "Attempted to send on non-active state: %d\n", conn->conn_state); msg_info_destroy(cut_handle, msg_node); pthread_mutex_unlock(&(conn->conn_mutex)); return(-1); } new_channel = new_cut_channel_out(cut_handle, conn, CHANNEL_MSG, msg_len, msg_node, message, 0); if(new_channel == 0) { cutlass_sysmsg(cut_handle, CUT_ERROR, "cutlass_msg_send: error allocating channel\n"); msg_info_destroy(cut_handle, msg_node); pthread_mutex_unlock(&(conn->conn_mutex)); return(-1); } transport_info = &(conn->out_channels[new_channel]); cutlass_time(&now); cutlass_transport_init_send(cut_handle, conn, transport_info, &now); pthread_mutex_unlock(&(conn->conn_mutex)); return(new_channel + CUT_NUM_CHANNELS); } /* * cutlass_msg_broadcast will send a message to all existing * remote connections. Returns 0 on success, 1 on nonfatal error, * -1 on fatal error. */ int cutlass_msg_broadcast(cutlass_t *cut_handle, char *message) { uint8_t conn_array[CUT_HK_ARRAY_SZ * CUT_ID_LEN]; uint8_t *array_loc; int i; int num_conn; int retval; if((NULL == cut_handle) || (NULL == message)) { cutlass_sysmsg(cut_handle, CUT_ERROR, "cutlass_msg_broadcast: Passed a NULL pointer\n"); return(1); } num_conn = cutlass_conn_list(cut_handle, conn_array, CUT_HK_ARRAY_SZ); array_loc = conn_array; for (i = 0; i < num_conn; i++) { retval = cutlass_msg_send(cut_handle, array_loc, message); if(retval < 0) { cutlass_sysmsg(cut_handle, CUT_ERROR, "cutlass_msg_broadcast: Received fatal error\n"); return(-1); } array_loc += CUT_ID_LEN; } return(0); } /* * Cutlass_msg_groupcast sends a message to all connections in a group. * This will call cutlass_msg_send for each connection. */ /* int cutlass_msg_groupcast(cutlass_t *cut_handle, struct cutlass_group *group, uint8_t *message) { int retval; struct cutlass_group_node *node; pthread_mutex_lock(&(group->group_mutex)); node = group->group_node_head; while(node != NULL) { retval = cutlass_msg_send(cut_handle, node->conn, message); if(retval < 0) { cutlass_conn_del(cut_handle, node->conn); } node = node->next; } pthread_mutex_unlock(&(group->group_mutex)); return(0); }*/