static void z_header_set_destroy_foreach(gpointer key G_GNUC_UNUSED, gpointer value, gpointer user_data G_GNUC_UNUSED) { z_enter(); z_header_set_destroy_chain((GList *)value); z_return(); }
/** * anypy_proxy_new: * @params: parameters for the AnyPyProxy class constructor * * This function is called upon startup to create a new AnyPy proxy. **/ ZProxy * anypy_proxy_new(ZProxyParams *params) { AnyPyProxy *self; z_enter(); self = Z_CAST(z_proxy_new(Z_CLASS(AnyPyProxy), params), AnyPyProxy); z_return(&self->super); }
/** * finger_proxy_new: * @params: ZProxyParams structure * * Finger proxy constructor. Allocates and initializes a proxy instance, * starts proxy thread. **/ static ZProxy * finger_proxy_new(ZProxyParams *params) { FingerProxy *self; z_enter(); self = Z_CAST(z_proxy_new(Z_CLASS(FingerProxy), params), FingerProxy); z_return((ZProxy *) self); }
/** * Reads some data from the blob into a buffer. * * @param[in] self this * @param[in] pos position to read from * @param[in] data buffer to read into * @param[in] req_datalen bytes to read * @param[in] timeout timeout * * @returns The amount of data actually read. **/ gsize z_blob_get_copy(ZBlob *self, gint64 pos, gchar* data, gsize req_datalen, gint timeout) { off_t err; gssize rd = 0; z_enter(); g_assert(self); g_assert(data); g_assert(pos >= 0); if (pos < self->size) { if (req_datalen > (guint64) (self->size - pos)) req_datalen = self->size - pos; if (z_blob_lock(self, timeout)) { if (self->is_in_file) { gssize remain; err = lseek(self->fd, pos, SEEK_SET); if (err < 0) { z_log(NULL, CORE_ERROR, 0, "Blob error, lseek() failed; file='%s', error='%s'", self->filename, g_strerror(errno)); g_assert(0); } remain = req_datalen; while (remain > 0) { rd = read(self->fd, data, remain); if (rd < 0) { if (errno == EINTR) { continue; } else { z_log(NULL, CORE_ERROR, 0, "Blob error, read() failed; file='%s', error='%s'", self->filename, g_strerror(errno)); g_assert(0); } } remain -= rd; } } else { memmove(data, self->data + pos, req_datalen); rd = req_datalen; } self->stat.req_rd++; self->stat.total_rd += rd; self->stat.last_accessed = time(NULL); z_blob_unlock(self); } } z_return(rd); }
/** * Get the (absolute) filename assigned to the blob. * * @param[in] self this * @param[in] user Owner of the created file or NULL * @param[in] group Group of the created file or NULL * @param[in] mode Mode of the created file of -1 * @param[in] timeout timeout * * @returns The filename **/ const gchar * z_blob_get_file(ZBlob *self, const gchar *user, const gchar *group, gint mode, gint timeout) { const gchar *res = NULL; z_enter(); g_assert(self); if (!self->filename || !self->system) z_return(NULL); if (z_blob_lock(self, timeout)) { if (!self->is_in_file) { if (self->storage_locked) goto exit; g_mutex_lock(self->system->mtx_blobsys); /* swap_out() accesses the blob systems data directly, so it needs to be locked */ z_blob_swap_out(self); g_mutex_unlock(self->system->mtx_blobsys); } if (group || user) { uid_t user_id = -1; gid_t group_id = -1; if (user && !z_resolve_user(user, &user_id)) { z_log(NULL, CORE_ERROR, 3, "Cannot resolve user; user='******'", user); goto exit; } if (group && !z_resolve_group(group, &group_id)) { z_log(NULL, CORE_ERROR, 3, "Cannot resolve group; group='%s'", group); goto exit; } if (chown(self->filename, user_id, group_id) == -1) goto exit; } if ((mode != -1) && (chmod(self->filename, mode) == -1)) goto exit; res = self->filename; exit: if (res == NULL) z_blob_unlock(self); } z_return(res); }
/** * Destroy the default blob system. **/ void z_blob_system_default_destroy(void) { z_enter(); if (z_blob_system_default) { z_blob_system_unref(z_blob_system_default); z_blob_system_default = NULL; } z_return(); }
/** * Create a new ZCodeBase64Decode instance. * * @param[in] bufsize initial buffer size * @param[in] error_tolerant whether to be tolerant of errors in input * * @returns new object **/ ZCode * z_code_base64_decode_new(gint bufsize, gboolean error_tolerant) { ZCodeBase64Decode *self; z_enter(); self = g_new0(ZCodeBase64Decode, 1); z_code_base64_decode_init(self, bufsize, error_tolerant); z_leave(); return &self->super; }
/** * Initialize ZCodeBase64Decode instance. * * @param[in] self ZCodeBase64Decode instance * @param[in] bufsize initial buffer size * @param[in] error_tolerant whether to be tolerant of errors in input **/ static void z_code_base64_decode_init(ZCodeBase64Decode *self, gint bufsize, gboolean error_tolerant) { z_enter(); z_code_init(&self->super, bufsize); self->super.transform = z_code_base64_decode_transform; self->super.finish = z_code_base64_decode_finish; self->phase = 0; self->error_tolerant = error_tolerant; z_leave(); }
/** * Create a new ZCodeBase64Encode instance. * * @param[in] bufsize initial buffer size * @param[in] linelen line length in output * * @returns new object **/ ZCode* z_code_base64_encode_new(gint bufsize, gint linelen) { ZCodeBase64Encode *self; z_enter(); self = g_new0(ZCodeBase64Encode, 1); z_code_base64_encode_init(self, bufsize, linelen); z_leave(); return &self->super; }
/** * Initialize the default blob system. **/ void z_blob_system_default_init(void) { z_enter(); z_blob_system_default = z_blob_system_new(z_blob_system_default_tmpdir, z_blob_system_default_max_disk_usage, z_blob_system_default_max_mem_usage, z_blob_system_default_lowat, z_blob_system_default_hiwat, z_blob_system_default_noswap_max); z_return(); }
/** * Initialize ZCodeBase64Encode instance. * * @param[in] self ZCodeBase64Encode instance * @param[in] bufsize initial buffer size * @param[in] linelen line length in output **/ static void z_code_base64_encode_init(ZCodeBase64Encode *self, gint bufsize, gint linelen) { z_enter(); z_code_init(&self->super, bufsize); self->super.transform = z_code_base64_encode_transform; self->super.finish = z_code_base64_encode_finish; self->phase = 0; self->linepos = 0; self->linelen = linelen; z_leave(); }
GList * z_header_set_get_all_headers(ZHeaderSet *self) { GList *ret = NULL; z_enter(); g_hash_table_foreach(self->headers, z_header_set_append_foreach, &ret); ret = g_list_reverse(ret); z_return(ret); }
/** * binary -> base64 conversion * * @param[in] s this * @param[in] from_ source buffer * @param[in] fromlen source buffer length * * @returns Whether conversion succeeded **/ static gboolean z_code_base64_encode_transform(ZCode *s, const void *from_, gsize fromlen) { ZCodeBase64Encode *self = (ZCodeBase64Encode *) s; gsize pos, buf_used_orig; const guchar *from = from_; z_enter(); z_code_grow((ZCode*)self, z_code_calculate_growing(self->super.buf_used, fromlen, self->linelen)); /* This may allocate 4 excess bytes - but requires no further realloc()s. * Since the calculation uses buf_used, these 4 bytes won't accumulate, but * will be used in the future write()s, so the extra 4 is a grand total. */ z_log(NULL, CORE_DUMP, 8, "Encoding base64 data; len='%" G_GSIZE_FORMAT"', phase='%d', used='%" G_GSIZE_FORMAT "', partial='0x%02x'", fromlen, self->phase, self->super.buf_used, self->super.buf[self->super.buf_used]); z_log_data_dump(NULL, CORE_DEBUG, 8, from, fromlen); buf_used_orig = self->super.buf_used; for (pos = 0; pos < fromlen; pos++) { switch (self->phase) { case 0: /* no previous partial content, (00.. ...., 00.. ....) -> (00xx xxxx, 00xx ....) */ self->super.buf[self->super.buf_used] = from[pos] >> 2; z_code_base64_encode_fix(self, FALSE); self->super.buf[self->super.buf_used] = (from[pos] & 0x03) << 4; break; case 1: /* 2 upper bits already set, (00yy ...., 00.. ....) -> (00yy xxxx, 00xx xx..) */ self->super.buf[self->super.buf_used] |= from[pos] >> 4; z_code_base64_encode_fix(self, FALSE); self->super.buf[self->super.buf_used] = (from[pos] & 0x0f) << 2; break; case 2: /* 4 upper bits already set, (00yy yy.., 00.. ....) -> (00yy yyxx, 00xx xxxx) */ self->super.buf[self->super.buf_used] |= from[pos] >> 6; z_code_base64_encode_fix(self, FALSE); self->super.buf[self->super.buf_used] = from[pos] & 0x3f; z_code_base64_encode_fix(self, FALSE); break; } self->phase = (self->phase + 1) % 3; } z_log(NULL, CORE_DUMP, 8, "Encoded base64 data; len='%" G_GSIZE_FORMAT "', phase='%d', used='%" G_GSIZE_FORMAT "', partial='0x%02x'", self->super.buf_used - buf_used_orig, self->phase, self->super.buf_used, self->super.buf[self->super.buf_used]); z_log_data_dump(NULL, CORE_DEBUG, 8, self->super.buf + buf_used_orig, self->super.buf_used - buf_used_orig); z_leave(); return TRUE; }
/** * Release the lock on the blob after z_blob_get_file. * * @param[in] self this * * Besides releasing the lock itself, this function also updates the * blob size from the file size. **/ void z_blob_release_file(ZBlob *self) { struct stat st; z_enter(); g_assert(self); if (!fstat(self->fd, &st)) self->size = self->alloc_size = st.st_size; else z_log(NULL, CORE_ERROR, 3, "Cannot stat file on release, blob size may be incorrect from now;"); z_blob_unlock(self); z_return(); }
gboolean z_kzorp_get_lookup_result(gint fd, struct z_kzorp_lookup_result *result) { socklen_t size = sizeof(*result); z_enter(); if (getsockopt(fd, SOL_IP, SO_KZORP_RESULT, result, &size) < 0) { z_log(NULL, CORE_ERROR, 3, "Error querying KZorp lookup result; fd='%d', error='%s'", fd, g_strerror(errno)); z_return(FALSE); } z_return(TRUE); }
/** * Create a new blob. * * @param[in] sys Blob system to create the blob into * @param[in] initial_size Initial size to allocate. * * This function creates a new blob. If sys is NULL, z_blob_system_default will be used. * * @returns The new blob instance **/ ZBlob* z_blob_new(ZBlobSystem *sys, gsize initial_size) { ZBlob *self; z_enter(); if (!sys) sys = z_blob_system_default; if (!sys || !sys->active) z_return(NULL); self = g_new0(ZBlob, 1); self->system = sys; self->filename = g_strdup_printf("%s/blob_XXXXXX", self->system->dir); self->fd = mkstemp(self->filename); if (self->fd < 0) { z_log(NULL, CORE_ERROR, 2, "Error creating blob file: file='%s', error='%s'", self->filename, strerror(errno)); g_free(self->filename); g_free(self); z_return(NULL); } z_refcount_set(&self->ref_cnt, 1); self->size = 0; self->alloc_size = 0; self->data = NULL; self->is_in_file = FALSE; self->mtx_reply = g_mutex_new(); self->cond_reply = g_cond_new(); self->mapped_ptr = NULL; self->mapped_length = 0; self->storage_locked = FALSE; z_blob_statistic_init(&self->stat); self->mtx_lock = g_mutex_new(); g_mutex_lock(self->system->mtx_blobsys); self->system->blobs = g_list_append(self->system->blobs, self); g_mutex_unlock(self->system->mtx_blobsys); if (initial_size > 0) z_blob_alloc(self, initial_size); z_return(self); }
static void z_header_set_destroy_chain(GList *list) { ZHeader *header; z_enter(); while (list) { header = (ZHeader *)list->data; g_string_free(header->key, TRUE); g_string_free(header->value, TRUE); g_free(header); list = g_list_delete_link(list, list); } z_return(); }
/** * telnet_copy_buf: * @to: * @from: * @bytes: * * * * Returns: * */ static gint telnet_copy_buf(ZIOBufferDyn *to, ZIOBuffer *from, guint bytes) { guint i; z_enter(); if ((i = to->size - to->end) < bytes) { /* we must allocate more buffer space */ to->size += (1 + bytes / TELNET_BUFFER_SIZE) * TELNET_BUFFER_SIZE; to->buf = g_realloc(to->buf, to->size); } for (i = 0; to->end < to->size && from->ofs < from->end && i < bytes; to->end++, from->ofs++, i++) to->buf[to->end] = from->buf[from->ofs]; z_return(i == bytes); }
/** * Truncates/expands a blob. * * @param[in] self this * @param[in] pos position to truncate at * @param[in] timeout timeout * * @returns TRUE on success **/ gboolean z_blob_truncate(ZBlob *self, gint64 pos, gint timeout) { gboolean res = FALSE; z_enter(); g_assert(self); g_assert(pos >= 0); if (z_blob_lock(self, timeout)) { z_blob_alloc(self, pos); z_blob_unlock(self); res = TRUE; } z_return(res); }
void z_fd_get_peer_tos(gint fd, guint8 *tos) { gint tmp; gchar buf[256]; gboolean tos_found = FALSE; socklen_t buflen, len; z_enter(); *tos = 0; tmp = 1; if (setsockopt(fd, SOL_IP, IP_RECVTOS, &tmp, sizeof(tmp)) < 0) { z_log(NULL, CORE_ERROR, 8, "Error in setsockopt(SOL_IP, IP_RECVTOS); fd='%d', error='%s'", fd, g_strerror(errno)); z_leave(); return; } buflen = sizeof(buf); if (getsockopt(fd, SOL_IP, IP_PKTOPTIONS, &buf, &buflen) >= 0) { struct msghdr msg; struct cmsghdr *cmsg; msg.msg_controllen = buflen; msg.msg_control = buf; for (cmsg = CMSG_FIRSTHDR(&msg); cmsg; cmsg = CMSG_NXTHDR(&msg, cmsg)) { if (cmsg->cmsg_level == SOL_IP && cmsg->cmsg_type == IP_TOS) { *tos = *(guchar *) CMSG_DATA(cmsg); tos_found = TRUE; break; } } } if (!tos_found) { len = sizeof(*tos); if (getsockopt(fd, SOL_IP, IP_TOS, tos, &len) == -1) { z_log(NULL, CORE_ERROR, 2, "Error in getsockopt(SOL_IP, IP_PKTOPTIONS) || getsockopt(SOL_IP, IP_TOS); fd='%d', error='%s'", fd, g_strerror(errno)); *tos = 0; } } z_leave(); }
/** * Writes a blob out to disk, called only from z_blob_system_threadproc() * * @param[in] self this * * @warning Caller must hold a lock BOTH on the blob AND the blob system! **/ static void z_blob_swap_out(ZBlob *self) { off_t err; gssize written, remain; z_enter(); g_assert(self); if (!self->storage_locked && !self->is_in_file && self->system) { err = lseek(self->fd, 0, SEEK_SET); if (err < 0) { z_log(NULL, CORE_ERROR, 0, "Blob error, lseek() failed; file='%s', error='%s'", self->filename, g_strerror(errno)); g_assert(0); } remain = self->size; while (remain > 0) { written = write(self->fd, self->data, remain); if (written < 0) { if (errno == EINTR) { continue; } else { z_log(NULL, CORE_ERROR, 0, "Blob error, write() failed; file='%s', error='%s'", self->filename, g_strerror(errno)); g_assert(0); } } remain -= written; } self->is_in_file = 1; g_free(self->data); self->data = NULL; self->stat.swap_count++; self->stat.last_accessed = time(NULL); self->system->mem_used -= self->alloc_size; self->system->disk_used += self->alloc_size; } z_return(); }
/** * Lock a blob. * * @param[in] self this * @param[in] timeout Timeout for locking. A negative value means infinite and thus blocking mode. Zero means nonblocking mode. * * @returns TRUE if successfully locked. **/ gboolean z_blob_lock(ZBlob *self, gint timeout) { gboolean res; struct timeval tvnow, tvfinish; z_enter(); g_assert(self); if (timeout < 0) /* infinite timeout -> blocking mode */ { g_mutex_lock(self->mtx_lock); res = TRUE; } else if (timeout == 0) /* zero timeout -> nonblocking mode */ { res = g_mutex_trylock(self->mtx_lock); } else /* positive timeout */ { gettimeofday(&tvfinish, NULL); tvfinish.tv_sec += (timeout / 1000); tvfinish.tv_usec += 1000 * (timeout % 1000); tvfinish.tv_sec += (tvfinish.tv_usec / 1000000); tvfinish.tv_usec %= 1000000; /* FIXME: maybe g_cond_wait_timed_wait ? */ do { res = FALSE; if (g_mutex_trylock(self->mtx_lock)) { res = TRUE; break; } usleep(1000); gettimeofday(&tvnow, NULL); } while ((tvnow.tv_sec < tvfinish.tv_sec) || ((tvnow.tv_sec == tvfinish.tv_sec) && (tvnow.tv_usec < tvfinish.tv_usec))); } z_return(res); }
/** * Decrease reference count of blob; destroy it if the count reaches zero. * * @param[in] self this **/ void z_blob_unref(ZBlob *self) { z_enter(); if (self && z_refcount_dec(&self->ref_cnt)) { g_mutex_lock(self->system->mtx_blobsys); self->alloc_req = -self->alloc_size; self->system->blobs = g_list_remove(self->system->blobs, self); z_blob_check_alloc(self); g_mutex_unlock(self->system->mtx_blobsys); if (self->data) g_free(self->data); if (self->fd >= 0) close(self->fd); if (self->filename) { if (unlink(self->filename)) z_log(NULL, CORE_ERROR, 3, "Error removing blob file, unlink() failed; file='%s', error='%s'", self->filename, strerror(errno)); g_free(self->filename); self->filename = NULL; } g_mutex_free(self->mtx_reply); g_cond_free(self->cond_reply); if (g_mutex_trylock(self->mtx_lock)) { g_mutex_unlock(self->mtx_lock); g_mutex_free(self->mtx_lock); } else { z_log(NULL, CORE_ERROR, 3, "Error while destroying blob, someone still has a lock on it;"); /* someone has locked the blob by z_blob_get_file or _get_ptr, and forgot to release it */ } g_free(self); } z_return(); }
/** * Finalize Base64 decoding. * * @param[in] s ZCodeBase64Decode instance * * Checks if the input was complete (if so, we returned to phase 0). * If it wasn't, the error is logged; and if we're not error_tolerant, * the return value also indicates this error condition. * * @return always TRUE if error_tolerant; otherwise FALSE if the input was incomplete **/ static gboolean z_code_base64_decode_finish(ZCode *s) { ZCodeBase64Decode *self = (ZCodeBase64Decode *) s; z_enter(); if (self->phase != 0) { z_log(NULL, CORE_ERROR, 3, "Unfinished base64 encoding; phase='%d'", self->phase); self->phase = 0; if (!self->error_tolerant) { z_leave(); return FALSE; } } z_leave(); return TRUE; }
/** * Unlocks a blob locked by 'z_blob_get_ptr()'. * * @param[in] self this * @param[in] data Pointer to a range, obtained by 'z_blob_get_ptr()' **/ void z_blob_free_ptr(ZBlob *self, gchar *data) { guint offset_in_page; z_enter(); g_assert(self); g_assert(self->mapped_ptr); g_assert(self->mapped_ptr == data); g_assert(self->mapped_length > 0); if (self->is_in_file) { offset_in_page = GPOINTER_TO_UINT(data) % getpagesize(); munmap(data - offset_in_page, self->mapped_length + offset_in_page); } self->mapped_ptr = NULL; self->mapped_length = 0; z_blob_unlock(self); z_return(); }
ZHeader * z_header_set_iterate(ZHeaderSet *self, gchar *key, gpointer *opaque) { ZHeader *res; GList *value = opaque ? (GList *) *opaque : NULL; z_enter(); if (value == NULL) value = (GList *) g_hash_table_lookup(self->headers, key); else value = g_list_next(value); if (value == NULL) z_return(NULL); res = value->data; if (opaque) *opaque = value; z_return(res); }
/** * Obtains a pointer to a subrange of the blob. * * @param[in] self this * @param[in] pos start of the range to get ptr for * @param[in, out] req_datalen length of the range: in=requested, out=mapped * @param[in] timeout timeout * * This function obtains a pointer to a specified subrange of the blob. * Until the pointer is freed by 'z_blob_free_ptr()', the blob will be locked for * reading, that means read operations are still possible, but writes and * swapping is disabled and will block! * * @returns The pointer on success, NULL on error **/ gchar * z_blob_get_ptr(ZBlob *self, gint64 pos, gsize *req_datalen, gint timeout) { gchar *data = NULL; gint offset_in_page; z_enter(); g_assert(self); g_assert(req_datalen); g_assert(self->mapped_ptr == NULL); g_assert(pos >= 0); if ((pos < self->size) && (self->size > 0) && z_blob_lock(self, timeout)) { if (self->size < (pos + (gssize) *req_datalen)) *req_datalen = self->size - pos; if (self->is_in_file) { offset_in_page = pos % getpagesize(); data = (gchar*)mmap(NULL, *req_datalen + offset_in_page, PROT_READ | PROT_WRITE, MAP_SHARED, self->fd, pos - offset_in_page); if (data == (gchar*)-1) data = NULL; else data += offset_in_page; } else { data = self->data + pos; } self->mapped_ptr = data; self->mapped_length = *req_datalen; if (!data) z_blob_unlock(self); } z_return(data); }
gboolean z_header_set_add(ZHeaderSet *self, GString *key, GString *value, gboolean multiple) { ZHeader *header; GList *hlist; z_enter(); header = g_new0(ZHeader, 1); header->key = key; header->value = value; hlist = g_hash_table_lookup(self->headers, header->key->str); if (!hlist || (header->key->str[0] == 'X') || multiple) { self->headers_count++; hlist = g_list_append(hlist, header); g_hash_table_insert(self->headers, header->key->str, hlist); z_return(TRUE); } z_return(FALSE); }
/** * z_dispatch_chain_new: * @protocol Protocol identifier (ZD_PROTO_*) * @bind_addr Address to bind to * @params Additional parameters (see ZDispatch*Params) * * Constructor of ZDispatchChain, allocates and initialises a new instance, optionally * starts a processing thread for it. * * Returns: * The new instance */ static ZDispatchChain * z_dispatch_chain_new(const gchar *session_id, ZDispatchBind *key, ZDispatchParams *params) { ZDispatchChain *self = g_new0(ZDispatchChain, 1); gchar thread_name[256], buf[256]; z_enter(); self->session_id = strdup(session_id); self->ref_cnt = 1; self->registered_key = z_dispatch_bind_ref(key); self->threaded = ((ZDispatchCommonParams *) params)->threaded; memcpy(&self->params, params, sizeof(*params)); if (self->threaded) { self->accept_queue = g_async_queue_new(); z_dispatch_chain_ref(self); g_snprintf(thread_name, sizeof(thread_name), "dispatch(%s)", z_dispatch_bind_format(key, buf, sizeof(buf))); if (!z_thread_new(thread_name, z_dispatch_chain_thread, self)) { /*LOG This message indicates that Zorp was unable to create a dispatcher thread for accepting new connection, and it is reverting back to the original non-threaded mode. It is likely that Zorp reached its thread or resource limit. Check your logs for further information. */ z_log(NULL, CORE_ERROR, 2, "Error creating dispatch thread, falling back to non-threaded mode;"); z_dispatch_chain_unref(self); self->threaded = FALSE; g_async_queue_unref(self->accept_queue); self->accept_queue = NULL; } } z_return(self); }
gboolean z_policy_tuple_get_verdict(ZPolicyObj *tuple, guint *verdict) { ZPolicyObj *tmp; z_enter(); if (!z_policy_seq_check(tuple)) { if (z_policy_var_parse(tuple, "i", verdict)) z_return(TRUE); /* not a sequence nor an int */ z_return(FALSE); } tmp = z_policy_seq_getitem(tuple, 0); if (!tmp || !z_policy_var_parse(tmp, "i", verdict)) { /* policy syntax error */ z_policy_var_unref(tmp); z_return(FALSE); } z_policy_var_unref(tmp); z_return(TRUE); }