/* * table_control.c * * Code controlling read and write access to the connections and groups * hashtables * * These functions should be the ONLY ones locking the hashtable-protecting * mutexes! * * Copyright (c) 2004 Todd MacDermid * */ #include #include #include #include /* * hashtable_fd_add adds the connection conn to the hashtable, using the * file descriptor stored in conn->socket as the key. Returns 0 on * success, -1 on failure. */ int hashtable_fd_add(cutlass_t *cut_handle, conn_t *conn) { int *fd; if((cut_handle == NULL) || (conn == NULL)) { cutlass_sysmsg(cut_handle, CUT_ERROR, "hashtable_fd_add: Passed a NULL handle\n"); return(-1); } if(conn->socket < 1) { cutlass_sysmsg(cut_handle, CUT_ERROR, "hashtable_fd_add: Connection socket too low\n"); return(-1); } if((fd = malloc(sizeof(int))) == NULL) { cutlass_sysmsg(cut_handle, CUT_ERROR, "hashtable_fd_add: Could not allocate memory\n"); return(-1); } *fd = conn->socket; cutlass_sysmsg(cut_handle, CUT_DEBUG, "hashtable_fd_add locking htab\n"); pthread_mutex_lock(&(cut_handle->htab_mutex)); if(cut_handle->running_state > 0) { if(hadd(cut_handle->connections, fd, sizeof(fd), conn) == FALSE) { cutlass_sysmsg(cut_handle, CUT_ERROR, "hashtable_fd_add: key already existed\n"); free(fd); } cutlass_sysmsg(cut_handle, CUT_DEBUG, "hashtable_fd_add unlocking htab\n"); } else { free(fd); } pthread_mutex_unlock(&(cut_handle->htab_mutex)); return(0); } /* * hashtable_addr_add adds the connection conn to the hashtable, using the * remote IP address conn->remote_addr as the key. Returns 0 on * success, -1 on failure. */ int hashtable_addr_add(cutlass_t *cut_handle, conn_t *conn) { struct sockaddr_in *addr; if((cut_handle == NULL) || (conn == NULL)) { cutlass_sysmsg(cut_handle, CUT_ERROR, "hashtable_addr_add: Passed a NULL handle\n"); return(-1); } if((addr = malloc(sizeof(struct sockaddr_in))) == NULL) { cutlass_sysmsg(cut_handle, CUT_ERROR, "hashtable_addr_add: Could not allocate memory\n"); return(-1); } memcpy(addr, &(conn->remote_addr), sizeof(struct sockaddr_in)); cutlass_sysmsg(cut_handle, CUT_DEBUG, "hashtable_addr_add locking htab\n"); pthread_mutex_lock(&(cut_handle->htab_mutex)); if(cut_handle->running_state > 0) { if(hadd(cut_handle->connections, addr, sizeof(struct sockaddr_in), conn) == FALSE) { cutlass_sysmsg(cut_handle, CUT_ERROR, "hashtable_addr_add: addr key already existed\n"); free(addr); } cutlass_sysmsg(cut_handle, CUT_DEBUG, "hashtable_fd_add unlocking htab\n"); } else { free(addr); } pthread_mutex_unlock(&(cut_handle->htab_mutex)); return(0); } int hashtable_fingerprint_add(cutlass_t *cut_handle, conn_t *conn, uint8_t *tmp_fingerprint) { uint8_t *fingerprint; if((cut_handle == NULL) || (conn == NULL)) { cutlass_sysmsg(cut_handle, CUT_ERROR, "hashtable_fingerprint_add: Passed a NULL handle\n"); return(-1); } if((fingerprint = malloc(CUT_ID_LEN)) == NULL) { cutlass_sysmsg(cut_handle, CUT_ERROR, "hashtable_fingerprint_add: Could not allocate memory\n"); return(-1); } memcpy(fingerprint, tmp_fingerprint, CUT_ID_LEN); cutlass_sysmsg(cut_handle, CUT_DEBUG, "hashtable_fingerprint_add locking htab\n"); pthread_mutex_lock(&(cut_handle->htab_mutex)); if(cut_handle->running_state > 0) { if(hadd(cut_handle->connections, fingerprint, CUT_ID_LEN, conn) == FALSE) { cutlass_sysmsg(cut_handle, CUT_ERROR, "hashtable_fingerprint_add: " "fingerprint key already existed."); free(fingerprint); pthread_mutex_unlock(&(cut_handle->htab_mutex)); return(1); } cutlass_sysmsg(cut_handle, CUT_DEBUG, "hashtable_fingerprint_add unlocking htab\n"); } else { free(fingerprint); } pthread_mutex_unlock(&(cut_handle->htab_mutex)); return(0); } /* * hashtable_group_add adds the group to the hashtable, using the * group_id within the group structure as the key. Returns 0 on * success, -1 on failure. */ int hashtable_group_add(cutlass_t *cut_handle, group_t *group) { uint8_t *group_key; if((NULL == cut_handle) || (NULL == group)) { cutlass_sysmsg(cut_handle, CUT_ERROR, "hashtable_group_add: Passed a NULL handle\n"); return(-1); } group_key = calloc(1, CUT_ID_LEN); if(NULL == group_key) { cutlass_sysmsg(cut_handle, CUT_ERROR, "hashtable_group_add: Could not allocate memory\n"); return(-1); } memcpy(group_key, group->group_id, CUT_ID_LEN); pthread_mutex_lock(&(cut_handle->group_mutex)); if(cut_handle->running_state > 0) { if(hadd(cut_handle->groups, group_key, CUT_ID_LEN) == FALSE) { cutlass_sysmsg(cut_handle, CUT_ERROR, "hashtable_group_add: group key already existed\n"); free(group_key); } } else { free(group_key); } pthread_mutex_unlock(&(cut_handle->group_mutex)); return(0); } /* * hashtable_fd_find locates the connection corresponding to file * descriptor fd, and returns a pointer to it, or NULL if no connection * is found. */ conn_t * hashtable_fd_find(cutlass_t *cut_handle, int fd) { conn_t *found_conn; if(cut_handle == NULL) { cutlass_sysmsg(cut_handle, CUT_ERROR, "hashtable_fd_find: Passed a NULL handle\n"); return(NULL); } found_conn = NULL; cutlass_sysmsg(cut_handle, CUT_DEBUG, "hashtable_fd_find locking htab\n"); pthread_mutex_lock(&(cut_handle->htab_mutex)); if(cut_handle->running_state > 0) { if(hfind(cut_handle->connections, &fd, sizeof(fd)) == TRUE) { found_conn = hstuff(cut_handle->connections); cutlass_sysmsg(cut_handle, CUT_DEBUG, "hashtable_fd_find locking conn\n"); pthread_mutex_lock(&(found_conn->conn_mutex)); } cutlass_sysmsg(cut_handle, CUT_DEBUG, "hashtable_fd_find unlocking htab\n"); } pthread_mutex_unlock(&(cut_handle->htab_mutex)); return(found_conn); } conn_t * cutlass_addr_find(cutlass_t *cut_handle, struct sockaddr_in *addr) { conn_t *found_conn; if((cut_handle == NULL) || (addr == NULL)) { cutlass_sysmsg(cut_handle, CUT_ERROR, "cutlass_addr_find: Passed a NULL handle\n"); return(NULL); } found_conn = NULL; cutlass_sysmsg(cut_handle, CUT_DEBUG, "cutlass_addr_find locking htab\n"); pthread_mutex_lock(&(cut_handle->htab_mutex)); if(cut_handle->running_state > 0) { if(hfind(cut_handle->connections, addr, sizeof(struct sockaddr_in)) == TRUE) { found_conn = hstuff(cut_handle->connections); cutlass_sysmsg(cut_handle, CUT_DEBUG, "cutlass_addr_find locking conn\n"); pthread_mutex_lock(&(found_conn->conn_mutex)); } cutlass_sysmsg(cut_handle, CUT_DEBUG, "cutlass_addr_find unlocking htab\n"); } pthread_mutex_unlock(&(cut_handle->htab_mutex)); return(found_conn); } /* * hashtable_fingerprint_find locates and locks a connection based * on the fingerprint passed in. Returns a pointer to the (newly locked) * conn_t on success, NULL on failure. */ conn_t * hashtable_fingerprint_find(cutlass_t *cut_handle, uint8_t *fingerprint) { conn_t *found_conn; if((cut_handle == NULL) || (fingerprint == NULL)) { cutlass_sysmsg(cut_handle, CUT_ERROR, "cutlass_keyid_find: Passed a NULL handle\n"); return(NULL); } found_conn = NULL; cutlass_sysmsg(cut_handle, CUT_DEBUG, "hashtable_fingerprint_find locking htab\n"); pthread_mutex_lock(&(cut_handle->htab_mutex)); if(cut_handle->running_state > 0) { if(hfind(cut_handle->connections, fingerprint, CUT_ID_LEN) == TRUE) { found_conn = hstuff(cut_handle->connections); cutlass_sysmsg(cut_handle, CUT_DEBUG, "hashtable_fingerprint_find locking conn\n"); pthread_mutex_lock(&(found_conn->conn_mutex)); } cutlass_sysmsg(cut_handle, CUT_DEBUG, "hashtable_fingerprint_find unlocking htab\n"); } pthread_mutex_unlock(&(cut_handle->htab_mutex)); return(found_conn); } /* * hashtable_addr_find locates the connection corresponding to the remote * address addr, and returns a pointer to it, or NULL if no connection * is found. */ conn_t * hashtable_addr_find(cutlass_t *cut_handle, struct sockaddr_in *addr) { conn_t *found_conn; if((cut_handle == NULL) || (addr == NULL)) { cutlass_sysmsg(cut_handle, CUT_ERROR, "hashtable_addr_find: Passed a NULL handle\n"); return(NULL); } found_conn = NULL; cutlass_sysmsg(cut_handle, CUT_DEBUG, "hashtable_addr_find locking htab\n"); pthread_mutex_lock(&(cut_handle->htab_mutex)); if(cut_handle->running_state > 0) { if(hfind(cut_handle->connections, addr, sizeof(struct sockaddr_in)) == TRUE) { found_conn = hstuff(cut_handle->connections); cutlass_sysmsg(cut_handle, CUT_DEBUG, "hashtable_addr_find locking conn\n"); pthread_mutex_lock(&(found_conn->conn_mutex)); } cutlass_sysmsg(cut_handle, CUT_DEBUG, "hashtable_addr_find unlocking htab\n"); } pthread_mutex_unlock(&(cut_handle->htab_mutex)); return(found_conn); } /* * hashtable_group_find locates the group corresponding to the provided * group_id, and returns a pointer to it, or NULL if no connection * is found. */ group_t * hashtable_group_find(cutlass_t *cut_handle, uint8_t *group_id) { group_t *found_group; if((cut_handle == NULL) || (group_id == NULL)) { cutlass_sysmsg(cut_handle, CUT_ERROR, "hashtable_group_find: Passed a NULL handle\n"); return(NULL); } found_group = NULL; pthread_mutex_lock(&(cut_handle->group_mutex)); if(cut_handle->running_state > 0) { if(hfind(cut_handle->groups, group_id, CUT_ID_LEN) == TRUE) found_group = hstuff(cut_handle->groups); } pthread_mutex_unlock(&(cut_handle->group_mutex)); return(found_group); } /* * hashtable_fd_del deletes the key corresponding to the file descriptor * fd from the hashtable, and frees the memory used by that key. * Returns 0 on successful deletion, or -1 if no such key was found. */ int hashtable_fd_del(cutlass_t *cut_handle, int fd) { if(cut_handle == NULL) { cutlass_sysmsg(cut_handle, CUT_ERROR, "hashtable_fd_del: Passed a NULL handle\n"); return(-1); } cutlass_sysmsg(cut_handle, CUT_DEBUG, "hashtable_fd_del locking htab\n"); pthread_mutex_lock(&(cut_handle->htab_mutex)); if(cut_handle->running_state > 0) { if(hfind(cut_handle->connections, &fd, sizeof(fd)) == TRUE) { free(hkey(cut_handle->connections)); hdel(cut_handle->connections); cutlass_sysmsg(cut_handle, CUT_DEBUG, "hashtable_fd_del unlocking htab 0\n"); pthread_mutex_unlock(&(cut_handle->htab_mutex)); return(0); } } cutlass_sysmsg(cut_handle, CUT_DEBUG, "hashtable_fd_del unlocking htab -1\n"); pthread_mutex_unlock(&(cut_handle->htab_mutex)); return(-1); } /* * hashtable_addr_del deletes the key corresponding to the remote address * addr from the hashtable, and frees the memory used by that key. * Returns 0 on successful deletion, or -1 if no such key was found. */ int hashtable_addr_del(cutlass_t *cut_handle, struct sockaddr_in *addr) { if((cut_handle == NULL) || (addr == NULL)) { cutlass_sysmsg(cut_handle, CUT_ERROR, "hashtable_addr_del: Passed a NULL handle\n"); return(-1); } cutlass_sysmsg(cut_handle, CUT_DEBUG, "hashtable_addr_del locking htab\n"); pthread_mutex_lock(&(cut_handle->htab_mutex)); if(cut_handle->running_state > 0) { if(hfind(cut_handle->connections, addr, sizeof(struct sockaddr_in)) == TRUE) { free(hkey(cut_handle->connections)); hdel(cut_handle->connections); } } cutlass_sysmsg(cut_handle, CUT_DEBUG, "hashtable_addr_del unlocking htab 0\n"); pthread_mutex_unlock(&(cut_handle->htab_mutex)); return(0); } int hashtable_fingerprint_del(cutlass_t *cut_handle, uint8_t *fingerprint) { if((cut_handle == NULL) || (fingerprint == NULL)) { cutlass_sysmsg(cut_handle, CUT_ERROR, "hashtable_fingerprint_del: Passed a NULL handle\n"); return(-1); } cutlass_sysmsg(cut_handle, CUT_DEBUG, "hashtable_fingerprint_del locking htab\n"); pthread_mutex_lock(&(cut_handle->htab_mutex)); if(cut_handle->running_state > 0) { if(hfind(cut_handle->connections, fingerprint, CUT_ID_LEN) == TRUE) { free(hkey(cut_handle->connections)); hdel(cut_handle->connections); } } cutlass_sysmsg(cut_handle, CUT_DEBUG, "hashtable_fingerprint_del unlocking htab 0\n"); pthread_mutex_unlock(&(cut_handle->htab_mutex)); return(0); } /* * hashtable_conn_del deletes all keys associated with the connection * conn from the hashtable, and frees the memory associated with those * keys. It does not free the memory used by the connection structure * itself (The "stuff" in the hashtable), leaving that to the * housekeeping thread. (As it may still have a pointer to it from * an older cutlass_conn_list() call). * * Returns 0 on success, or -1 on failure. */ int hashtable_conn_del(cutlass_t *cut_handle, conn_t *conn) { if((cut_handle == NULL) || (conn == NULL)) { cutlass_sysmsg(cut_handle, CUT_ERROR, "hashtable_conn_del: Passed a NULL handle\n"); return(-1); } cutlass_sysmsg(cut_handle, CUT_DEBUG, "hashtable_conn_del locking htab\n"); pthread_mutex_lock(&(cut_handle->htab_mutex)); if(cut_handle->running_state > 0) { if(conn->socket > 1) { if(hfind(cut_handle->connections, &(conn->socket), sizeof(int)) == TRUE) { free(hkey(cut_handle->connections)); hdel(cut_handle->connections); } } if(hfind(cut_handle->connections, &(conn->remote_addr), sizeof(struct sockaddr_in)) == TRUE) { free(hkey(cut_handle->connections)); hdel(cut_handle->connections); } if(hfind(cut_handle->connections, conn->fingerprint, CUT_ID_LEN) == TRUE) { free(hkey(cut_handle->connections)); hdel(cut_handle->connections); } } cutlass_sysmsg(cut_handle, CUT_DEBUG, "hashtable_conn_del unlocking htab\n"); pthread_mutex_unlock(&(cut_handle->htab_mutex)); return(0); } /* * hashtable_group_del deletes all keys associated with the group * from the hashtable, and frees the memory associated with those * keys. It does not free the memory used by the group structure * itself (The "stuff" in the hashtable), leaving that to the * caller * * Returns 0 on success, or -1 on failure. */ int hashtable_group_del(cutlass_t *cut_handle, uint8_t *group_id) { if((cut_handle == NULL) || (group_id == NULL)) { cutlass_sysmsg(cut_handle, CUT_ERROR, "hashtable_group_del: Passed a NULL handle\n"); return(-1); } pthread_mutex_lock(&(cut_handle->group_mutex)); if(cut_handle->running_state > 0) { if(hfind(cut_handle->groups, group_id, CUT_ID_LEN) == TRUE) { free(hkey(cut_handle->groups)); hdel(cut_handle->groups); pthread_mutex_unlock(&(cut_handle->group_mutex)); return(0); } } pthread_mutex_unlock(&(cut_handle->group_mutex)); return(-1); } /* * internal_conn_list is used by housekeeping, which does not need to * increase the reference count of connections it obtains lists of. * (because it is what checks the reference count anyways). */ int internal_conn_list(cutlass_t *cut_handle, conn_t **conn_array, int max_conn) { int i; int more; if((cut_handle == NULL) || (conn_array == NULL)) { cutlass_sysmsg(cut_handle, CUT_ERROR, "cutlass_conn_list: Passed a NULL handle\n"); return(-1); } i = 0; more = 1; pthread_mutex_lock(&(cut_handle->htab_mutex)); if(cut_handle->running_state > 0) { if(hfirst(cut_handle->connections) == TRUE) { while((i < max_conn) && (more == 1)) { if(hkeyl(cut_handle->connections) != sizeof(int)) { conn_array[i] = hstuff(cut_handle->connections); i++; } if(hnext(cut_handle->connections)== FALSE) { more = 0; } } } } pthread_mutex_unlock(&(cut_handle->htab_mutex)); return(i); } /* * cutlass_conn_list fills in memory with an array of all * connections currently in the hashtable. This is so the * housekeeping thread has something to iterate over. It will * fill in a maximum of max_conn entries. * * Returns the number of entries in the array on success, or * -1 on an error. */ int cutlass_conn_list(cutlass_t *cut_handle, uint8_t *fingerprints, int max_conn) { int i; int more; uint8_t *array_loc; if((cut_handle == NULL) || (fingerprints == NULL)) { cutlass_sysmsg(cut_handle, CUT_ERROR, "cutlass_conn_list: Passed a NULL handle\n"); return(-1); } i = 0; more = 1; array_loc = fingerprints; pthread_mutex_lock(&(cut_handle->htab_mutex)); if(cut_handle->running_state > 0) { if(hfirst(cut_handle->connections) == TRUE) { while((i < max_conn) && (more == 1)) { if(hkeyl(cut_handle->connections) == CUT_ID_LEN) { memcpy(array_loc, hkey(cut_handle->connections), CUT_ID_LEN); array_loc += CUT_ID_LEN; i++; } if(hnext(cut_handle->connections)== FALSE) { more = 0; } } } } pthread_mutex_unlock(&(cut_handle->htab_mutex)); return(i); }