/** * Copy data to the compression buffer of a connection. We do collect * some data there until it's full so that we can achieve better * compression ratios. * If the (pre-)compression buffer is full, we try to flush it ("actually * compress some data") and to add the new (uncompressed) data afterwards. * This function closes the connection on error. * @param Idx Connection handle. * @param Data Pointer to the data. * @param Len Length of the data to add. * @return true on success, false otherwise. */ GLOBAL bool Zip_Buffer( CONN_ID Idx, const char *Data, size_t Len ) { size_t buflen; assert( Idx > NONE ); assert( Data != NULL ); assert( Len > 0 ); buflen = array_bytes(&My_Connections[Idx].zip.wbuf); if (buflen + Len >= WRITEBUFFER_SLINK_LEN) { /* compression buffer is full, flush */ if( ! Zip_Flush( Idx )) return false; } /* check again; if zip buf is still too large do not append data: * otherwise the zip wbuf would grow too large */ buflen = array_bytes(&My_Connections[Idx].zip.wbuf); if (buflen + Len >= WRITEBUFFER_SLINK_LEN) { Log(LOG_ALERT, "Zip Write buffer space exhausted: %lu bytes", buflen + Len); Conn_Close(Idx, "Zip Write buffer space exhausted", NULL, false); return false; } return array_catb(&My_Connections[Idx].zip.wbuf, Data, Len); } /* Zip_Buffer */
static ssize_t handle_read( const int64 clientsocket ) { struct http_data* h = io_getcookie( clientsocket ); ssize_t l; if( ( l = io_tryread( clientsocket, static_inbuf, sizeof static_inbuf ) ) <= 0 ) { handle_dead( clientsocket ); return 0; } /* If we get the whole request in one packet, handle it without copying */ if( !array_start( &h->request ) ) { if( memchr( static_inbuf, '\n', l ) ) return http_handle_request( clientsocket, static_inbuf, l ); h->flag |= STRUCT_HTTP_FLAG_ARRAY_USED; array_catb( &h->request, static_inbuf, l ); return 0; } h->flag |= STRUCT_HTTP_FLAG_ARRAY_USED; array_catb( &h->request, static_inbuf, l ); if( array_failed( &h->request ) ) return http_issue_error( clientsocket, CODE_HTTPERROR_500 ); if( ( array_bytes( &h->request ) > 8192 ) && !accesslist_isblessed( (char*)&h->ip, OT_PERMISSION_MAY_SYNC ) ) return http_issue_error( clientsocket, CODE_HTTPERROR_500 ); if( memchr( array_start( &h->request ), '\n', array_bytes( &h->request ) ) ) return http_handle_request( clientsocket, array_start( &h->request ), array_bytes( &h->request ) ); return 0; }
/** * Compress data in ZIP buffer and move result to the write buffer of * the connection. * This function closes the connection on error. * @param Idx Connection handle. * @return true on success, false otherwise. */ GLOBAL bool Zip_Flush( CONN_ID Idx ) { int result; unsigned char zipbuf[WRITEBUFFER_SLINK_LEN]; int zipbuf_used = 0; z_stream *out; out = &My_Connections[Idx].zip.out; out->avail_in = (uInt)array_bytes(&My_Connections[Idx].zip.wbuf); if (!out->avail_in) return true; /* nothing to do. */ out->next_in = array_start(&My_Connections[Idx].zip.wbuf); assert(out->next_in != NULL); out->next_out = zipbuf; out->avail_out = (uInt)sizeof zipbuf; #ifdef DEBUG_ZIP Log(LOG_DEBUG, "out->avail_in %d, out->avail_out %d", out->avail_in, out->avail_out); #endif result = deflate( out, Z_SYNC_FLUSH ); if(( result != Z_OK ) || ( out->avail_in > 0 )) { Log( LOG_ALERT, "Compression error: code %d!?", result ); Conn_Close( Idx, "Compression error!", NULL, false ); return false; } if (out->avail_out <= 0) { /* Not all data was compressed, because data became * bigger while compressing it. */ Log(LOG_ALERT, "Compression error: buffer overflow!?"); Conn_Close(Idx, "Compression error!", NULL, false); return false; } assert(out->avail_out <= WRITEBUFFER_SLINK_LEN); zipbuf_used = WRITEBUFFER_SLINK_LEN - out->avail_out; #ifdef DEBUG_ZIP Log(LOG_DEBUG, "zipbuf_used: %d", zipbuf_used); #endif if (!array_catb(&My_Connections[Idx].wbuf, (char *)zipbuf, (size_t) zipbuf_used)) { Log (LOG_ALERT, "Compression error: can't copy data!?"); Conn_Close(Idx, "Compression error!", NULL, false); return false; } My_Connections[Idx].bytes_out += zipbuf_used; My_Connections[Idx].zip.bytes_out += array_bytes(&My_Connections[Idx].zip.wbuf); array_trunc(&My_Connections[Idx].zip.wbuf); return true; } /* Zip_Flush */
unsigned long scan_to_array(unsigned long (*func)(const char*,char*,unsigned long*), const char* src,array* dest) { unsigned long scanned; unsigned long needed=str_len(src); char* x=((char*)array_start(dest))+array_bytes(dest); if (!array_allocate(dest,1,array_bytes(dest)+needed-1)) return 0; return func(src,x,&scanned); }
static int cdbb_handle_ops(struct cdbb *a) { int i; int num; struct op *t; num = 0; for (i = 0; i < a->tnum; i++) { t = &a->ops[i]; if (t->kf) { /* trigger was fired */ switch (t->t) { case O_ADD: case O_ADD_MOD: /* fall-trought */ case O_MOD: cdb_make_add(a->w, (unsigned char *)t->n.p, array_bytes(&t->n), (unsigned char *)t->v.p, array_bytes(&t->v)); num++; break; case O_DEL: /* do nothing, fall-trough */ case O_NONE: default: break; } } else { switch (t->t) { case O_ADD_MOD: /* key not found so add, fall-trough */ case O_ADD: cdb_make_add(a->w, (unsigned char *)t->n.p, array_bytes(&t->n), (unsigned char *)t->v.p, array_bytes(&t->v)); num++; break; case O_DEL: /* key not found error */ break; case O_MOD: /* key not found error */ break; case O_NONE: /* fall-trought */ default: break; } } } return num; }
int main() { array_t array = ARRAY_INIT(4); array_resize(&array, 3); if (array_bytes(&array) != 12) return 1; array_fail(&array); if (array_bytes(&array) != 0) return 2; return 0; }
void fmt_to_array(size_t (*func)(char*,const char*,size_t), array* a,const char* src,size_t len) { size_t needed=func(0,src,len); if (array_bytes(a)+needed>=needed && array_allocate(a,1,array_bytes(a)+needed-1)) { char* x=((char*)array_start(a))+array_bytes(a)-needed; func(x,src,len); } else array_fail(a); }
void fmt_tofrom_array(unsigned long (*func)(char*,const char*,unsigned long), array* dest,array* src) { unsigned long needed; char* x; if (array_failed(dest) || array_failed(src)) { array_fail(dest); return; } needed=func(0,array_start(src),array_bytes(src)); if (array_allocate(dest,1,array_bytes(dest)+needed-1)) { x=((char*)array_start(dest))+array_bytes(dest)-needed; func(x,array_start(src),array_bytes(src)); } else array_fail(dest); }
void fmt_tofrom_array(size_t (*func)(char*,const char*,size_t), array* dest,array* src) { size_t needed; char* x; if (array_failed(dest) || array_failed(src)) { array_fail(dest); return; } needed=func(0,array_start(src),array_bytes(src)); if (array_bytes(dest)+needed>needed && array_allocate(dest,1,array_bytes(dest)+needed-1)) { x=((char*)array_start(dest))+array_bytes(dest)-needed; func(x,array_start(src),array_bytes(src)); } else array_fail(dest); }
size_t scan_tofrom_array(size_t (*func)(const char*,char*,size_t*), array* src,array* dest) { size_t scanned; size_t needed; char* x; array_cat0(src); if (array_failed(src) || array_failed(dest)) return 0; needed=array_bytes(src); x=((char*)array_start(dest))+array_bytes(dest); if (!array_allocate(dest,1,array_bytes(dest)+needed-1)) return 0; needed=func(array_start(src),x,&scanned); array_truncate(src,1,array_bytes(src)-1); return needed; }
/** * Handler for the IRC "HELP" command. * * @param Client The client from which this command has been received. * @param Req Request structure with prefix and all parameters. * @return CONNECTED or DISCONNECTED. */ GLOBAL bool IRC_HELP(CLIENT *Client, REQUEST *Req) { COMMAND *cmd; assert(Client != NULL); assert(Req != NULL); if ((Req->argc == 0 && array_bytes(&Conf_Helptext) > 0) || (Req->argc >= 1 && strcasecmp(Req->argv[0], "Commands") != 0)) { /* Help text available and requested */ if (Req->argc >= 1) return Help(Client, Req->argv[0]); if (!Help(Client, "Intro")) return DISCONNECTED; return CONNECTED; } cmd = Parse_GetCommandStruct(); while(cmd->name) { if (!IRC_WriteStrClient(Client, "NOTICE %s :%s", Client_ID(Client), cmd->name)) return DISCONNECTED; cmd++; } return CONNECTED; } /* IRC_HELP */
static bool ConnSSL_LoadServerKey_gnutls(void) { int err; const char *cert_file; err = gnutls_certificate_allocate_credentials(&x509_cred); if (err < 0) { Log(LOG_ERR, "gnutls_certificate_allocate_credentials: %s", gnutls_strerror(err)); return false; } cert_file = Conf_SSLOptions.CertFile ? Conf_SSLOptions.CertFile:Conf_SSLOptions.KeyFile; if (!cert_file) { Log(LOG_NOTICE, "No SSL server key configured, SSL disabled."); return false; } if (array_bytes(&Conf_SSLOptions.KeyFilePassword)) Log(LOG_WARNING, "Ignoring KeyFilePassword: Not supported by GNUTLS."); if (!Load_DH_params()) return false; gnutls_certificate_set_dh_params(x509_cred, dh_params); err = gnutls_certificate_set_x509_key_file(x509_cred, cert_file, Conf_SSLOptions.KeyFile, GNUTLS_X509_FMT_PEM); if (err < 0) { Log(LOG_ERR, "gnutls_certificate_set_x509_key_file (cert %s, key %s): %s", cert_file, Conf_SSLOptions.KeyFile ? Conf_SSLOptions.KeyFile : "(NULL)", gnutls_strerror(err)); return false; } return true; }
GLOBAL void Channel_SetTopic(CHANNEL *Chan, CLIENT *Client, const char *Topic) { size_t len; assert( Chan != NULL ); assert( Topic != NULL ); len = strlen(Topic); if (len < array_bytes(&Chan->topic)) array_free(&Chan->topic); if (len >= COMMAND_LEN || !array_copyb(&Chan->topic, Topic, len+1)) Log(LOG_WARNING, "could not set new Topic \"%s\" on %s: %s", Topic, Chan->name, strerror(errno)); #ifndef STRICT_RFC Chan->topic_time = time(NULL); if (Client != NULL && Client_Type(Client) != CLIENT_SERVER) strlcpy(Chan->topic_who, Client_ID(Client), sizeof Chan->topic_who); else strlcpy(Chan->topic_who, DEFAULT_TOPIC_ID, sizeof Chan->topic_who); #else (void) Client; #endif } /* Channel_SetTopic */
static void Set_KeyFile(CHANNEL *Chan, const char *KeyFile) { size_t len; assert(Chan != NULL); assert(KeyFile != NULL); len = strlen(KeyFile); if (len < array_bytes(&Chan->keyfile)) { Log(LOG_INFO, "Channel key file of %s removed.", Chan->name); array_free(&Chan->keyfile); } if (len < 1) return; if (!array_copyb(&Chan->keyfile, KeyFile, len+1)) Log(LOG_WARNING, "Could not set new channel key file \"%s\" for %s: %s", KeyFile, Chan->name, strerror(errno)); else Log(LOG_INFO|LOG_snotice, "New local channel key file \"%s\" for %s activated.", KeyFile, Chan->name); } /* Set_KeyFile */
/** * Send help for a given topic to the client. * * @param Client The client requesting help. * @param Topic The help topic requested. * @return CONNECTED or DISCONNECTED. */ static bool Help(CLIENT *Client, const char *Topic) { char *line; size_t helptext_len, len_str, idx_start, lines = 0; bool in_article = false; assert(Client != NULL); assert(Topic != NULL); helptext_len = array_bytes(&Conf_Helptext); line = array_start(&Conf_Helptext); while (helptext_len > 0) { len_str = strlen(line) + 1; assert(helptext_len >= len_str); helptext_len -= len_str; if (in_article) { /* The first character in each article text line must * be a TAB (ASCII 9) character which will be stripped * in the output. If it is not a TAB, the end of the * article has been reached. */ if (line[0] != '\t') { if (lines > 0) return CONNECTED; else break; } /* A single '.' character indicates an empty line */ if (line[1] == '.' && line[2] == '\0') idx_start = 2; else idx_start = 1; if (!IRC_WriteStrClient(Client, "NOTICE %s :%s", Client_ID(Client), &line[idx_start])) return DISCONNECTED; lines++; } else { if (line[0] == '-' && line[1] == ' ' && strcasecmp(&line[2], Topic) == 0) in_article = true; } line += len_str; } /* Help topic not found (or empty)! */ if (!IRC_WriteStrClient(Client, "NOTICE %s :No help for \"%s\" found!", Client_ID(Client), Topic)) return DISCONNECTED; return CONNECTED; }
/* append trailing NUL byte to array, but do not count it. */ bool array_cat0_temporary(array * a) { char *endpos = array_alloc(a, 1, array_bytes(a)); if (!endpos) return false; *endpos = '\0'; return true; }
void delete_entry(struct cdbb *a, struct taia *k) { char pk[TAIA_PACK]; array dayidx; memset(&dayidx, 0, sizeof(array)); fmt_day_idx(&dayidx, k); taia_pack(pk, k); cdbb_del(a, pk, TAIA_PACK); cdbb_del_val(a, dayidx.p, array_bytes(&dayidx), pk, TAIA_PACK); blog_modified(a); }
int main(void) { struct array arr; int i; test_assert(array_init(&arr, 10, sizeof(int))); test_assert(array_bytes(&arr) == 0); test_assert(array_size(&arr) == 0); for (i = 0; i < 20; ++i) { test_assert(array_size(&arr) == i); test_assert(array_bytes(&arr) == i * sizeof(int)); test_assert(array_cat(&arr, &i) == 1); } test_assert(array_size(&arr) == 20); test_assert(array_bytes(&arr) == 20 * sizeof(int)); array_free(&arr); test_assert(array_bytes(&arr) == 0); test_assert(array_size(&arr) == 0); return 0; }
/* LEVLEL COPYING LOGIC */ static int cdbb_check_ops(struct cdbb *a, unsigned char *k, size_t ks, unsigned char *v, size_t vs) { struct op *t; int i, f; f = 0; for (i = 0; i < a->tnum; i++) { t = &a->ops[i]; if (array_bytes(&t->n) == ks && !memcmp(k, t->n.p, ks) && ks) { t->kf = 1; if (t->t != O_ADD) f = 1; /* no value trigger */ if ((array_bytes(&t->v) != 0)) { if (t->t == O_MOD || t->t == O_ADD_MOD) continue; /* value trigger */ t->sv = realloc(t->sv, vs); if (t->sv == NULL) continue; memcpy(t->sv, v, vs); /* values do match */ if (!memcmp(t->v.p, t->sv, vs)) t->vf = 1; else f = 0; /* reset found */ } } } return f; }
void add_entry(struct cdbb *a, struct taia *k, char *v, size_t vs) { char pk[TAIA_PACK]; array dayidx; memset(&dayidx, 0, sizeof(array)); fmt_day_idx(&dayidx, k); taia_pack(pk, k); /* entry + idx */ cdbb_add(a, pk, TAIA_PACK, v, vs); cdbb_add(a, dayidx.p, array_bytes(&dayidx), pk, TAIA_PACK); blog_modified(a); array_reset(&dayidx); }
static int pem_passwd_cb(char *buf, int size, int rwflag, void *password) { array *pass = password; int passlen; (void)rwflag; /* rwflag is unused if DEBUG is not set. */ assert(rwflag == 0); /* 0 -> callback used for decryption. * See SSL_CTX_set_default_passwd_cb(3) */ passlen = (int) array_bytes(pass); LogDebug("pem_passwd_cb buf size %d, array size %d", size, passlen); assert(passlen >= 0); if (passlen <= 0) { Log(LOG_ERR, "PEM password required but not set [in pem_passwd_cb()]!"); return 0; } size = passlen > size ? size : passlen; memcpy(buf, (char *)(array_start(pass)), size); return size; }
int64 iob_send(int64 s,io_batch* b) { /* Windows has a sendfile called TransmitFile, which can send one * header and one trailer buffer. */ iob_entry* x,* last; io_entry* e; int64 sent; int i; if (b->bytesleft==0) return 0; sent=-1; e=iarray_get(&io_fds,s); if (!e) { errno=EBADF; return -3; } if (!(x=array_get(&b->b,sizeof(iob_entry),b->next))) return -3; /* can't happen error */ last=(iob_entry*)(((char*)array_start(&b->b))+array_bytes(&b->b)); fprintf(stderr,"iob_send() called!\n"); if (e->canwrite || e->sendfilequeued==1) { fprintf(stderr,"...reaping finished WriteFile/TransmitFile.\n"); /* An overlapping write finished. Reap the result. */ if (e->bytes_written==-1) return -3; if (e->bytes_written<x->n) { sent=e->bytes_written; if (x->n < e->bytes_written) { e->bytes_written-=x->n; x->n=0; ++x; } x->n -= e->bytes_written; x->offset += e->bytes_written; b->bytesleft -= e->bytes_written; } e->canwrite=0; e->sendfilequeued=0; } for (i=0; x+i<last; ++i) if (x[i].n) break; if (x[i].type==FROMBUF) { fprintf(stderr,"found non-sent buffer batch entry at %d\n",i); if (x+i+1 < last && (x[i+1].type==FROMFILE)) { fprintf(stderr,"Next is a file, can use TransmitFile\n",i); TRANSMIT_FILE_BUFFERS tfb; e->sendfilequeued=1; memset(&tfb,0,sizeof(tfb)); memset(&e[i].os,0,sizeof(e[i].os)); e[i].os.Offset=x[i].offset; e[i].os.OffsetHigh=(x[i].offset>>32); fprintf(stderr,"Calling TransmitFile on %p...",s); if (!TransmitFile(s,(HANDLE)x[i].fd, x[i].n+tfb.HeadLength>0xffff?0xffff:x[i].n, 0,&e[i].os,&tfb,TF_USE_KERNEL_APC)) { if (GetLastError()==ERROR_IO_PENDING) { fprintf(stderr," pending.!\n"); e->writequeued=1; errno=EAGAIN; e->errorcode=0; return -1; } else { fprintf(stderr," failed!\n"); e->errorcode=errno; return -3; } } fprintf(stderr," OK!\n"); return sent; } else {
/** * uncompress data and copy it to read buffer. * Returns true if data has been unpacked or no * compressed data is currently pending in the zread buffer. * This function closes the connection on error. * @param Idx Connection handle. * @return true on success, false otherwise. */ GLOBAL bool Unzip_Buffer( CONN_ID Idx ) { int result; unsigned char unzipbuf[READBUFFER_LEN]; int unzipbuf_used = 0; unsigned int z_rdatalen; unsigned int in_len; z_stream *in; assert( Idx > NONE ); z_rdatalen = (unsigned int)array_bytes(&My_Connections[Idx].zip.rbuf); if (z_rdatalen == 0) return true; in = &My_Connections[Idx].zip.in; in->next_in = array_start(&My_Connections[Idx].zip.rbuf); assert(in->next_in != NULL); in->avail_in = z_rdatalen; in->next_out = unzipbuf; in->avail_out = (uInt)sizeof unzipbuf; #ifdef DEBUG_ZIP Log(LOG_DEBUG, "in->avail_in %d, in->avail_out %d", in->avail_in, in->avail_out); #endif result = inflate( in, Z_SYNC_FLUSH ); if( result != Z_OK ) { Log(LOG_ALERT, "Decompression error: %s (code=%d, ni=%d, ai=%d, no=%d, ao=%d)!?", in->msg, result, in->next_in, in->avail_in, in->next_out, in->avail_out); Conn_Close(Idx, "Decompression error!", NULL, false); return false; } assert(z_rdatalen >= in->avail_in); in_len = z_rdatalen - in->avail_in; unzipbuf_used = READBUFFER_LEN - in->avail_out; #ifdef DEBUG_ZIP Log(LOG_DEBUG, "unzipbuf_used: %d - %d = %d", READBUFFER_LEN, in->avail_out, unzipbuf_used); #endif assert(unzipbuf_used <= READBUFFER_LEN); if (!array_catb(&My_Connections[Idx].rbuf, (char*) unzipbuf, (size_t)unzipbuf_used)) { Log (LOG_ALERT, "Decompression error: can't copy data!?"); Conn_Close(Idx, "Decompression error!", NULL, false); return false; } if( in->avail_in > 0 ) { array_moveleft(&My_Connections[Idx].zip.rbuf, 1, in_len ); } else { array_trunc( &My_Connections[Idx].zip.rbuf ); My_Connections[Idx].zip.bytes_in += unzipbuf_used; } return true; } /* Unzip_Buffer */