/* * action.c * * Cutlass action object handling code * * Copyright (c) 2004,2005 Todd MacDermid * Nash Foster * John Schweitzer * Jack Lloyd */ #include #include #include #include #include void * action_thread(void *void_object) { struct action_combo *combo_object; cutlass_t *cut_handle; struct cut_action_obj *action_obj; cut_action_handler action_handler; combo_object = void_object; if(NULL == combo_object) { cutlass_sysmsg(NULL, CUT_ERROR, "action_thread: Got a NULL combo_object\n"); goto end; } cut_handle = combo_object->cut_handle; action_obj = combo_object->action_obj; action_handler = combo_object->action_handler; if(NULL == action_obj) { cutlass_sysmsg(cut_handle, CUT_ERROR, "action_thread: Got a NULL action object\n"); goto end2; } if(NULL == cut_handle) { cutlass_sysmsg(cut_handle, CUT_ERROR, "action_thread: Got a NULL cut_handle\n"); goto end3; } if(cut_handle->action_lock) { pthread_mutex_lock(&(cut_handle->action_mutex)); action_handler(cut_handle, action_obj); pthread_mutex_unlock(&(cut_handle->action_mutex)); } else { action_handler(cut_handle, action_obj); } /* Fall-through is intentional */ end3: free(action_obj); end2: free(combo_object); end: return(NULL); } /* * cutlass_action is used to call the action handler registered * by the user. It determines which action handler to call based * on the action_type passed through in the action_object. */ /* Add mutexen and thread fork to the below */ int cutlass_action(cutlass_t *cut_handle, conn_t *conn, struct cut_action_obj *action_obj) { cut_action_handler action_handler; pthread_t action_tid; struct action_combo *combo_object; struct cut_action_obj *new_action_obj; if((NULL == cut_handle) || (NULL == action_obj)){ cutlass_sysmsg(cut_handle, CUT_ERROR, "cutlass_action: Passed a NULL pointer\n"); return(-1); } action_obj->cut_handle = cut_handle; if(conn != NULL) { memcpy(action_obj->conn_fingerprint, conn->fingerprint, CUT_ID_LEN); } action_handler = cut_handle->action_handlers[action_obj->action_type]; if(action_handler == NULL) { return(-1); } else { combo_object = calloc(1, sizeof(struct action_combo)); if(NULL == combo_object) { cutlass_sysmsg(cut_handle, CUT_ERROR, "cutlass_action: Failed to allocate memory\n"); return(-1); } new_action_obj = calloc(1, sizeof(struct cut_action_obj)); if(NULL == new_action_obj) { cutlass_sysmsg(cut_handle, CUT_ERROR, "cutlass_action: Failed to allocate memory\n"); free(combo_object); return(-1); } memcpy(new_action_obj, action_obj, sizeof(struct cut_action_obj)); combo_object->cut_handle = cut_handle; combo_object->action_obj = new_action_obj; combo_object->action_handler = action_handler; if(pthread_create(&action_tid, NULL, action_thread, combo_object) < 0) { cutlass_sysmsg(cut_handle, CUT_ERROR, "cutlass_action: Failed to create new thread\n"); return(-1); } pthread_detach(action_tid); } return(0); } /* * cutlass_action_populate fills in an action object with the most * commonly used parameters, those pertaining to the current connection. * Not all actions use these, but enough do that it's worth it to break * out. * * Does not return values (because errors are coding errors, rather * than execution errors). It'll scream out an error message, though. */ void cutlass_action_populate(cutlass_t *cut_handle, conn_t *conn, struct cut_action_obj *action_obj) { if((NULL == cut_handle) || (NULL == conn) || (NULL == action_obj)) { cutlass_sysmsg(cut_handle, CUT_ERROR, "cutlass_action_populate: Passed a NULL pointer\n"); return; } strncpy(action_obj->remote_nick, conn->conn_name, CUTLASS_NAME_LEN-1); memcpy(&(action_obj->remote_addr), &(conn->remote_addr), sizeof(struct sockaddr_in)); memcpy(action_obj->conn_fingerprint, conn->fingerprint, CUT_ID_LEN); action_obj->cut_handle = cut_handle; action_obj->remote_key = copy_public_key(conn->peer_key); } /* * cutlass_sysmsg is the cutlass message passing code. Send a priority * and a format string, and if the priority is >= that set with * cutlass_set_verbose, it will either print it out or send it to the * set action handler. * * TODO - Multi-language support */ void cutlass_sysmsg(cutlass_t *cut_handle, int priority, const char *fmtstr, ...) { int timelen; struct cut_action_obj action_obj; struct timespec now; va_list substuff; /* make substuff point to first unnamed argument */ va_start(substuff, fmtstr); if(NULL == cut_handle) { vfprintf(stderr, fmtstr, substuff); } else if (cut_handle->verbose >= priority) { if (NULL == cut_handle->action_handlers[CUT_SYS_MSG]) { if(cut_handle->print_timestamp) { cutlass_time(&now); fprintf(stderr, "%d.%9d: ", now.tv_sec, now.tv_nsec); } vfprintf(stderr, fmtstr, substuff); } else { memset(&action_obj, 0, sizeof(struct cut_action_obj)); action_obj.action_type = CUT_SYS_MSG; if(cut_handle->print_timestamp) { cutlass_time(&now); snprintf(action_obj.msg, CUT_MSG_LEN_MAX-1, "%d.%9d: ", now.tv_sec, now.tv_nsec); timelen = strlen(action_obj.msg); vsnprintf(action_obj.msg + timelen, CUT_MSG_LEN_MAX-1-timelen, fmtstr, substuff); } else { vsnprintf(action_obj.msg, CUT_MSG_LEN_MAX-1, fmtstr, substuff); cutlass_action(cut_handle, NULL, &action_obj); } } } } /* * cutlass_action_cleanse zeroes out an action object. (Note, this * may be dead code) */ void cutlass_action_cleanse(struct cut_action_obj *action_object) { if(action_object != NULL) { memset(action_object, 0, sizeof(struct cut_action_obj)); } } /* * cutlass_action_type provides a safe way to extract the action_type * from an action_object. This is so an action_handler registered on * multiple action_types knows what it's been called for. * * Returns -1 on failure, the action_type on success. */ int cutlass_action_type(struct cut_action_obj *action_object) { if(NULL == action_object) { return(-1); } /* * just an int, no alloc needed. */ return (action_object->action_type); } /* * cutlass_action_channel_id provides a safe way to extract the external * channel_id from an action_object. This is so an action_handler for file * receiving, for example, knows what channel the file is coming in on, * so it will be able to poll said channel. * * Returns -1 on failure, the channel id on success. */ int cutlass_action_channel_id(struct cut_action_obj *action_object) { if(NULL == action_object) { return(-1); } /* * just an int, no alloc needed. */ return (action_object->external_channel_id); } /* * cutlass_action_rnick provides a safe API to extract the remote * nickname from the action_object. Returns NULL on failure, or * a pointer to a char array on success. The caller is responsible * for freeing this array! */ char * cutlass_action_rnick(struct cut_action_obj *action_object) { char *rval; size_t len = 0; if (NULL == action_object) return(NULL); if (NULL == action_object->remote_nick) return(NULL); len = strlen(action_object->remote_nick); rval = calloc(sizeof(char), len + 1); if (NULL == rval) return(NULL); strncpy(rval, action_object->remote_nick, len); return(rval); } /* * cutlass_action_gnick provides a safe API to extract the group * nickname from the action_object. Returns NULL on failure, or * a pointer to a char array on success. The caller is responsible * for freeing this array! */ char * cutlass_action_gnick(struct cut_action_obj *action_object) { char *rval; size_t nick_len = 0; if (NULL == action_object) return(NULL); if (NULL == action_object->group_nick) return(NULL); nick_len = strlen(action_object->group_nick); rval = calloc(sizeof(char), nick_len+1); if (NULL == rval) return (NULL); strncpy (rval, action_object->group_nick, nick_len); return (rval); } /* * cutlass_action_rkey provides a safe API to extract the remote * public key from the action_object. Returns NULL on failure, or * a pointer to a cutlass_keyset on success. The caller is responsible * for freeing this structure! */ cutlass_public_key cutlass_action_rkey(struct cut_action_obj *action_object) { if(action_object == NULL) { cutlass_public_key retval; cutlass_sysmsg(NULL, CUT_DEBUG, "cutlass_action_rkey: NULL action object"); retval.key = 0; return retval; } return copy_public_key(action_object->remote_key); } /* * cutlass_action_gkey provides a safe API to extract the group * public key from the action_object. Returns NULL on failure, or * a pointer to cutlass_keyset on success. The caller is responsible * for freeing this structure! */ cutlass_public_key cutlass_action_gkey(struct cut_action_obj *action_object) { if(action_object == NULL) { cutlass_public_key retval; cutlass_sysmsg(NULL, CUT_DEBUG, "cutlass_action_gkey: NULL action object"); retval.key = 0; return retval; } return copy_public_key(action_object->group_key); } /* * cutlass_action_fname provides a safe API to extract the filename * from the action_object. This obviously only works on file-related * actions. Returns NULL on failure, or * a pointer to a char array on success. The caller is responsible * for freeing this array! */ char * cutlass_action_fname(struct cut_action_obj *action_object) { char *rval; size_t len = 0; if (NULL == action_object) return(NULL); if (NULL == action_object->file_name) return(NULL); len = strlen (action_object->file_name); rval = calloc(sizeof(char), len+1); if (NULL == rval) return (NULL); strncpy (rval, action_object->file_name, len); return (rval); } /* * cutlass_action_fcsum provides a safe API to extract the file * checksum from the action_object. This obviously only works on * file-related actions. Returns NULL on failure, or * a pointer to a char array on success. The caller is responsible * for freeing this array! */ uint8_t * cutlass_action_fcsum(struct cut_action_obj *action_object) { char *rval; size_t len = 0; if (NULL == action_object) return(NULL); if (NULL == action_object->file_csum) return(NULL); len = strlen (action_object->file_csum); rval = calloc(sizeof(char), len + 1); if (NULL == rval) return (NULL); strncpy (rval, action_object->file_csum, len); return (rval); } /* * cutlass_action_fsize provides a safe API to extract the file size * from the action_object. This obviously only works on file-related * actions. Returns 0 on failure, or the file size on success. */ uint32_t cutlass_action_fsize(struct cut_action_obj *action_object) { if(action_object == NULL) return(0); /* * no need to calloc memory here, as we're just returning * an int */ return(action_object->file_size); } /* * cutlass_action_fingerprint returns a uint8_t* of the fingerprint for * action messages. Caller is responsible for freeing the uint8_t returned. */ uint8_t * cutlass_action_fingerprint (struct cut_action_obj *action_object) { uint8_t *tmp; if (NULL == action_object) return (NULL); tmp = (uint8_t *) calloc (1, CUT_ID_LEN); if (NULL == tmp) return (NULL); // proably shoudl bail the hell out if calloc fails. memcpy (tmp,action_object->conn_fingerprint, CUT_ID_LEN); return (tmp); } /* * cutlass_action_msg provides a safe API to extract the message * from an action_object. Only works on message actions. Returns * NULL on failure, or a pointer to a char array on success. The caller * is responsible for freeing this array! */ char * cutlass_action_msg(struct cut_action_obj *action_object) { char *rval = NULL; size_t len = 0; if (NULL == action_object) return (NULL); if (NULL == action_object->msg) return (NULL); len = strlen(action_object->msg); rval = calloc(1, len + 1); if (NULL == rval) return (NULL); strncpy(rval, action_object->msg, len); return(rval); } /* * cutlass_action_addr provides a safe API to extract the remote * address from the action_object. Returns NULL on failure, or * a pointer to a struct in_addr on success. The caller is responsible * for freeing this structure! */ struct in_addr * cutlass_action_addr(struct cut_action_obj *action_object) { struct in_addr *rval = NULL; if (NULL == action_object) return (NULL); // remote_addr is not a pointer rval = calloc (sizeof (struct in_addr), 1); if (NULL == rval) return (NULL); memcpy (rval, &((action_object->remote_addr).sin_addr), sizeof(struct in_addr)); return (rval); }