void init_fir(fir_t *fs, int N, int window, double alpha) { int i; double sw = 0.0; for (i = 0; i < NSTAGE; i++) { fs->sum[i] = 0; fs->i_w[i] = i * N / NSTAGE; } fs->out = 0; fs->ns = N; fs->w = (double *) balloc(fatal, N * sizeof(double)); if (window < wind_oldblast || window > wind_rect) window = wind_oldblast; for (i = 0; i < N; i++) { fs->w[i] = window_filt[window](i, N, alpha); sw += fs->w[i]; } for (i = 0; i < N; i++) { fs->w[i] /= sw; } }
int main(int argc, char *argv[]) { int r; DIR *root_dir; if (argc < 2) { fprintf(stderr, "Usage: mkfs fs.img files...\n"); exit(1); } assert((512 % sizeof(struct dinode)) == 0); assert((512 % sizeof(struct xv6_dirent)) == 0); fsfd = open(argv[1], O_RDWR | O_CREAT | O_TRUNC, 0666); if (fsfd < 0) { perror(argv[1]); exit(1); } mkfs(985, LOGSIZE, 1024); root_dir = opendir(argv[2]); root_inode = ialloc(T_DIR); assert(root_inode == ROOTINO); r = add_dir(root_dir, root_inode, root_inode); if (r != 0) { exit(EXIT_FAILURE); } balloc(usedblocks); exit(0); }
int stream_decrypt(buffer_t *ciphertext, cipher_ctx_t *cipher_ctx, size_t capacity) { if (cipher_ctx == NULL) return CRYPTO_ERROR; cipher_t *cipher = cipher_ctx->cipher; static buffer_t tmp = { 0, 0, 0, NULL }; int err = CRYPTO_OK; brealloc(&tmp, ciphertext->len, capacity); buffer_t *plaintext = &tmp; plaintext->len = ciphertext->len; if (!cipher_ctx->init) { if (cipher_ctx->chunk == NULL) { cipher_ctx->chunk = (buffer_t *)ss_malloc(sizeof(buffer_t)); memset(cipher_ctx->chunk, 0, sizeof(buffer_t)); balloc(cipher_ctx->chunk, cipher->nonce_len); } size_t left_len = min(cipher->nonce_len - cipher_ctx->chunk->len, ciphertext->len); if (left_len > 0) { memcpy(cipher_ctx->chunk->data + cipher_ctx->chunk->len, ciphertext->data, left_len); memmove(ciphertext->data, ciphertext->data + left_len, ciphertext->len - left_len); cipher_ctx->chunk->len += left_len; ciphertext->len -= left_len; } if (cipher_ctx->chunk->len < cipher->nonce_len) return CRYPTO_NEED_MORE; uint8_t *nonce = cipher_ctx->nonce; size_t nonce_len = cipher->nonce_len; plaintext->len -= left_len; memcpy(nonce, cipher_ctx->chunk->data, nonce_len); cipher_ctx_set_nonce(cipher_ctx, nonce, nonce_len, 0); cipher_ctx->counter = 0; cipher_ctx->init = 1; if (cipher->method >= RC4_MD5) { if (ppbloom_check((void *)nonce, nonce_len) == 1) { LOGE("crypto: stream: repeat IV detected"); return CRYPTO_ERROR; } } } if (ciphertext->len <= 0) return CRYPTO_NEED_MORE; if (cipher->method >= SALSA20) { int padding = cipher_ctx->counter % SODIUM_BLOCK_SIZE; brealloc(plaintext, (plaintext->len + padding) * 2, capacity); if (padding) { brealloc(ciphertext, ciphertext->len + padding, capacity); memmove(ciphertext->data + padding, ciphertext->data, ciphertext->len); sodium_memzero(ciphertext->data, padding); } crypto_stream_xor_ic((uint8_t *)plaintext->data, (const uint8_t *)(ciphertext->data), (uint64_t)(ciphertext->len + padding), (const uint8_t *)cipher_ctx->nonce, cipher_ctx->counter / SODIUM_BLOCK_SIZE, cipher->key, cipher->method); cipher_ctx->counter += ciphertext->len; if (padding) { memmove(plaintext->data, plaintext->data + padding, plaintext->len); } } else { err = cipher_ctx_update(cipher_ctx, (uint8_t *)plaintext->data, &plaintext->len, (const uint8_t *)(ciphertext->data), ciphertext->len); } if (err) return CRYPTO_ERROR; #ifdef SS_DEBUG dump("PLAIN", plaintext->data, plaintext->len); dump("CIPHER", ciphertext->data, ciphertext->len); #endif brealloc(ciphertext, plaintext->len, capacity); memcpy(ciphertext->data, plaintext->data, plaintext->len); ciphertext->len = plaintext->len; // Add to bloom filter if (cipher_ctx->init == 1) { if (cipher->method >= RC4_MD5) { ppbloom_add((void *)cipher_ctx->nonce, cipher->nonce_len); cipher_ctx->init = 2; } } return CRYPTO_OK; }
static void server_recv_cb(EV_P_ ev_io *w, int revents) { server_ctx_t *server_ctx = (server_ctx_t *)w; struct sockaddr_storage src_addr; memset(&src_addr, 0, sizeof(struct sockaddr_storage)); buffer_t *buf = ss_malloc(sizeof(buffer_t)); balloc(buf, buf_size); socklen_t src_addr_len = sizeof(struct sockaddr_storage); unsigned int offset = 0; #ifdef MODULE_REDIR char control_buffer[64] = { 0 }; struct msghdr msg; memset(&msg, 0, sizeof(struct msghdr)); struct iovec iov[1]; struct sockaddr_storage dst_addr; memset(&dst_addr, 0, sizeof(struct sockaddr_storage)); msg.msg_name = &src_addr; msg.msg_namelen = src_addr_len; msg.msg_control = control_buffer; msg.msg_controllen = sizeof(control_buffer); iov[0].iov_base = buf->data; iov[0].iov_len = buf_size; msg.msg_iov = iov; msg.msg_iovlen = 1; buf->len = recvmsg(server_ctx->fd, &msg, 0); if (buf->len == -1) { ERROR("[udp] server_recvmsg"); goto CLEAN_UP; } else if (buf->len > packet_size) { if (verbose) { LOGI("[udp] UDP server_recv_recvmsg fragmentation"); } } if (get_dstaddr(&msg, &dst_addr)) { LOGE("[udp] unable to get dest addr"); goto CLEAN_UP; } src_addr_len = msg.msg_namelen; #else ssize_t r; r = recvfrom(server_ctx->fd, buf->data, buf_size, 0, (struct sockaddr *)&src_addr, &src_addr_len); if (r == -1) { // error on recv // simply drop that packet ERROR("[udp] server_recv_recvfrom"); goto CLEAN_UP; } else if (r > packet_size) { if (verbose) { LOGI("[udp] server_recv_recvfrom fragmentation"); } } buf->len = r; #endif if (verbose) { LOGI("[udp] server receive a packet"); } #ifdef MODULE_REMOTE tx += buf->len; int err = server_ctx->crypto->decrypt_all(buf, server_ctx->crypto->cipher, buf_size); if (err) { // drop the packet silently goto CLEAN_UP; } #endif #ifdef MODULE_LOCAL #if !defined(MODULE_TUNNEL) && !defined(MODULE_REDIR) #ifdef __ANDROID__ tx += buf->len; #endif uint8_t frag = *(uint8_t *)(buf->data + 2); offset += 3; #endif #endif /* * * SOCKS5 UDP Request * +----+------+------+----------+----------+----------+ * |RSV | FRAG | ATYP | DST.ADDR | DST.PORT | DATA | * +----+------+------+----------+----------+----------+ * | 2 | 1 | 1 | Variable | 2 | Variable | * +----+------+------+----------+----------+----------+ * * SOCKS5 UDP Response * +----+------+------+----------+----------+----------+ * |RSV | FRAG | ATYP | DST.ADDR | DST.PORT | DATA | * +----+------+------+----------+----------+----------+ * | 2 | 1 | 1 | Variable | 2 | Variable | * +----+------+------+----------+----------+----------+ * * shadowsocks UDP Request (before encrypted) * +------+----------+----------+----------+ * | ATYP | DST.ADDR | DST.PORT | DATA | * +------+----------+----------+----------+ * | 1 | Variable | 2 | Variable | * +------+----------+----------+----------+ * * shadowsocks UDP Response (before encrypted) * +------+----------+----------+----------+ * | ATYP | DST.ADDR | DST.PORT | DATA | * +------+----------+----------+----------+ * | 1 | Variable | 2 | Variable | * +------+----------+----------+----------+ * * shadowsocks UDP Request and Response (after encrypted) * +-------+--------------+ * | IV | PAYLOAD | * +-------+--------------+ * | Fixed | Variable | * +-------+--------------+ * */ #ifdef MODULE_REDIR char addr_header[512] = { 0 }; int addr_header_len = construct_udprelay_header(&dst_addr, addr_header); if (addr_header_len == 0) { LOGE("[udp] failed to parse tproxy addr"); goto CLEAN_UP; } // reconstruct the buffer brealloc(buf, buf->len + addr_header_len, buf_size); memmove(buf->data + addr_header_len, buf->data, buf->len); memcpy(buf->data, addr_header, addr_header_len); buf->len += addr_header_len; #elif MODULE_TUNNEL char addr_header[512] = { 0 }; char *host = server_ctx->tunnel_addr.host; char *port = server_ctx->tunnel_addr.port; uint16_t port_num = (uint16_t)atoi(port); uint16_t port_net_num = htons(port_num); int addr_header_len = 0; struct cork_ip ip; if (cork_ip_init(&ip, host) != -1) { if (ip.version == 4) { // send as IPv4 struct in_addr host_addr; memset(&host_addr, 0, sizeof(struct in_addr)); int host_len = sizeof(struct in_addr); if (dns_pton(AF_INET, host, &host_addr) == -1) { FATAL("IP parser error"); } addr_header[addr_header_len++] = 1; memcpy(addr_header + addr_header_len, &host_addr, host_len); addr_header_len += host_len; } else if (ip.version == 6) { // send as IPv6 struct in6_addr host_addr; memset(&host_addr, 0, sizeof(struct in6_addr)); int host_len = sizeof(struct in6_addr); if (dns_pton(AF_INET6, host, &host_addr) == -1) { FATAL("IP parser error"); } addr_header[addr_header_len++] = 4; memcpy(addr_header + addr_header_len, &host_addr, host_len); addr_header_len += host_len; } else { FATAL("IP parser error"); } } else { // send as domain int host_len = strlen(host); addr_header[addr_header_len++] = 3; addr_header[addr_header_len++] = host_len; memcpy(addr_header + addr_header_len, host, host_len); addr_header_len += host_len; } memcpy(addr_header + addr_header_len, &port_net_num, 2); addr_header_len += 2; // reconstruct the buffer brealloc(buf, buf->len + addr_header_len, buf_size); memmove(buf->data + addr_header_len, buf->data, buf->len); memcpy(buf->data, addr_header, addr_header_len); buf->len += addr_header_len; #else char host[257] = { 0 }; char port[64] = { 0 }; struct sockaddr_storage dst_addr; memset(&dst_addr, 0, sizeof(struct sockaddr_storage)); int addr_header_len = parse_udprelay_header(buf->data + offset, buf->len - offset, host, port, &dst_addr); if (addr_header_len == 0) { // error in parse header goto CLEAN_UP; } char *addr_header = buf->data + offset; #endif #ifdef MODULE_LOCAL char *key = hash_key(server_ctx->remote_addr->sa_family, &src_addr); #else char *key = hash_key(dst_addr.ss_family, &src_addr); #endif struct cache *conn_cache = server_ctx->conn_cache; remote_ctx_t *remote_ctx = NULL; cache_lookup(conn_cache, key, HASH_KEY_LEN, (void *)&remote_ctx); if (remote_ctx != NULL) { if (sockaddr_cmp(&src_addr, &remote_ctx->src_addr, sizeof(src_addr))) { remote_ctx = NULL; } } // reset the timer if (remote_ctx != NULL) { ev_timer_again(EV_A_ & remote_ctx->watcher); } if (remote_ctx == NULL) { if (verbose) { #ifdef MODULE_REDIR char src[SS_ADDRSTRLEN]; char dst[SS_ADDRSTRLEN]; strcpy(src, get_addr_str((struct sockaddr *)&src_addr)); strcpy(dst, get_addr_str((struct sockaddr *)&dst_addr)); LOGI("[udp] cache miss: %s <-> %s", dst, src); #else LOGI("[udp] cache miss: %s:%s <-> %s", host, port, get_addr_str((struct sockaddr *)&src_addr)); #endif } } else { if (verbose) { #ifdef MODULE_REDIR char src[SS_ADDRSTRLEN]; char dst[SS_ADDRSTRLEN]; strcpy(src, get_addr_str((struct sockaddr *)&src_addr)); strcpy(dst, get_addr_str((struct sockaddr *)&dst_addr)); LOGI("[udp] cache hit: %s <-> %s", dst, src); #else LOGI("[udp] cache hit: %s:%s <-> %s", host, port, get_addr_str((struct sockaddr *)&src_addr)); #endif } } #ifdef MODULE_LOCAL #if !defined(MODULE_TUNNEL) && !defined(MODULE_REDIR) if (frag) { LOGE("[udp] drop a message since frag is not 0, but %d", frag); goto CLEAN_UP; } #endif const struct sockaddr *remote_addr = server_ctx->remote_addr; const int remote_addr_len = server_ctx->remote_addr_len; if (remote_ctx == NULL) { // Bind to any port int remotefd = create_remote_socket(remote_addr->sa_family == AF_INET6); if (remotefd < 0) { ERROR("[udp] udprelay bind() error"); goto CLEAN_UP; } setnonblocking(remotefd); #ifdef SO_NOSIGPIPE set_nosigpipe(remotefd); #endif #ifdef IP_TOS // Set QoS flag int tos = 46; setsockopt(remotefd, IPPROTO_IP, IP_TOS, &tos, sizeof(tos)); #endif #ifdef SET_INTERFACE if (server_ctx->iface) { if (setinterface(remotefd, server_ctx->iface) == -1) ERROR("setinterface"); } #endif #ifdef __ANDROID__ if (vpn) { if (protect_socket(remotefd) == -1) { ERROR("protect_socket"); close(remotefd); goto CLEAN_UP; } } #endif // Init remote_ctx remote_ctx = new_remote(remotefd, server_ctx); remote_ctx->src_addr = src_addr; remote_ctx->af = remote_addr->sa_family; remote_ctx->addr_header_len = addr_header_len; memcpy(remote_ctx->addr_header, addr_header, addr_header_len); // Add to conn cache cache_insert(conn_cache, key, HASH_KEY_LEN, (void *)remote_ctx); // Start remote io ev_io_start(EV_A_ & remote_ctx->io); ev_timer_start(EV_A_ & remote_ctx->watcher); } if (offset > 0) { buf->len -= offset; memmove(buf->data, buf->data + offset, buf->len); } int err = server_ctx->crypto->encrypt_all(buf, server_ctx->crypto->cipher, buf_size); if (err) { // drop the packet silently goto CLEAN_UP; } if (buf->len > packet_size) { if (verbose) { LOGI("[udp] server_recv_sendto fragmentation"); } } int s = sendto(remote_ctx->fd, buf->data, buf->len, 0, remote_addr, remote_addr_len); if (s == -1) { ERROR("[udp] server_recv_sendto"); } #else int cache_hit = 0; int need_query = 0; if (buf->len - addr_header_len > packet_size) { if (verbose) { LOGI("[udp] server_recv_sendto fragmentation"); } } if (remote_ctx != NULL) { cache_hit = 1; // detect destination mismatch if (remote_ctx->addr_header_len != addr_header_len || memcmp(addr_header, remote_ctx->addr_header, addr_header_len) != 0) { if (dst_addr.ss_family != AF_INET && dst_addr.ss_family != AF_INET6) { need_query = 1; } } else { memcpy(&dst_addr, &remote_ctx->dst_addr, sizeof(struct sockaddr_storage)); } } else { if (dst_addr.ss_family == AF_INET || dst_addr.ss_family == AF_INET6) { int remotefd = create_remote_socket(dst_addr.ss_family == AF_INET6); if (remotefd != -1) { setnonblocking(remotefd); #ifdef SO_BROADCAST set_broadcast(remotefd); #endif #ifdef SO_NOSIGPIPE set_nosigpipe(remotefd); #endif #ifdef IP_TOS // Set QoS flag int tos = 46; setsockopt(remotefd, IPPROTO_IP, IP_TOS, &tos, sizeof(tos)); #endif #ifdef SET_INTERFACE if (server_ctx->iface) { if (setinterface(remotefd, server_ctx->iface) == -1) ERROR("setinterface"); } #endif remote_ctx = new_remote(remotefd, server_ctx); remote_ctx->src_addr = src_addr; remote_ctx->server_ctx = server_ctx; remote_ctx->addr_header_len = addr_header_len; memcpy(remote_ctx->addr_header, addr_header, addr_header_len); memcpy(&remote_ctx->dst_addr, &dst_addr, sizeof(struct sockaddr_storage)); } else { ERROR("[udp] bind() error"); goto CLEAN_UP; } } } if (remote_ctx != NULL && !need_query) { size_t addr_len = get_sockaddr_len((struct sockaddr *)&dst_addr); int s = sendto(remote_ctx->fd, buf->data + addr_header_len, buf->len - addr_header_len, 0, (struct sockaddr *)&dst_addr, addr_len); if (s == -1) { ERROR("[udp] sendto_remote"); if (!cache_hit) { close_and_free_remote(EV_A_ remote_ctx); } } else { if (!cache_hit) { // Add to conn cache remote_ctx->af = dst_addr.ss_family; char *key = hash_key(remote_ctx->af, &remote_ctx->src_addr); cache_insert(server_ctx->conn_cache, key, HASH_KEY_LEN, (void *)remote_ctx); ev_io_start(EV_A_ & remote_ctx->io); ev_timer_start(EV_A_ & remote_ctx->watcher); } } } else { struct addrinfo hints; memset(&hints, 0, sizeof(struct addrinfo)); hints.ai_family = AF_UNSPEC; hints.ai_socktype = SOCK_DGRAM; hints.ai_protocol = IPPROTO_UDP; struct query_ctx *query_ctx = new_query_ctx(buf->data + addr_header_len, buf->len - addr_header_len); query_ctx->server_ctx = server_ctx; query_ctx->addr_header_len = addr_header_len; query_ctx->src_addr = src_addr; memcpy(query_ctx->addr_header, addr_header, addr_header_len); if (need_query) { query_ctx->remote_ctx = remote_ctx; } struct ResolvQuery *query = resolv_query(host, query_resolve_cb, NULL, query_ctx, htons(atoi(port))); if (query == NULL) { ERROR("[udp] unable to create DNS query"); close_and_free_query(EV_A_ query_ctx); goto CLEAN_UP; } query_ctx->query = query; } #endif CLEAN_UP: bfree(buf); ss_free(buf); }
sym_t *symEnter(sym_fd_t sd, char_t *name, value_t v, int arg) { sym_tabent_t *tp; sym_t *sp, *last; char_t *cp; int hindex; a_assert(name); a_assert(0 <= sd && sd < symMax); tp = sym[sd]; a_assert(tp); /* * Calculate the first daisy-chain from the hash table. If non-zero, then * we have daisy-chain, so scan it and look for the symbol. */ last = NULL; hindex = hashIndex(tp, name); if ((sp = tp->hash_table[hindex]) != NULL) { for (; sp; sp = sp->forw) { cp = sp->name.value.string; if (cp[0] == name[0] && gstrcmp(cp, name) == 0) { break; } last = sp; } if (sp) { /* * Found, so update the value * If the caller stores handles which require freeing, they * will be lost here. It is the callers responsibility to free * resources before overwriting existing contents. We will here * free allocated strings which occur due to value_instring(). * We should consider providing the cleanup function on the open rather * than the close and then we could call it here and solve the problem. */ if (sp->content.valid) { valueFree(&sp->content); } sp->content = v; sp->arg = arg; return sp; } /* * Not found so allocate and append to the daisy-chain */ sp = (sym_t*) balloc(B_L, sizeof(sym_t)); if (sp == NULL) { return NULL; } sp->name = valueString(name, VALUE_ALLOCATE); sp->content = v; sp->forw = (sym_t*) NULL; sp->arg = arg; last->forw = sp; } else { /* * Daisy chain is empty so we need to start the chain */ sp = (sym_t*) balloc(B_L, sizeof(sym_t)); if (sp == NULL) { return NULL; } tp->hash_table[hindex] = sp; tp->hash_table[hashIndex(tp, name)] = sp; sp->forw = (sym_t*) NULL; sp->content = v; sp->arg = arg; sp->name = valueString(name, VALUE_ALLOCATE); } return sp; }
struct sensor_sba_info *sensor_config_bus(int slave_addr, uint8_t dev_id, SBA_BUSID bus_id, SENSOR_BUS_TYPE bus_type, int req_num, BLOCK_TYPE block_type) { struct sensor_sba_req *reqs = NULL; struct sensor_sba_info *info = NULL; int i; reqs = (struct sensor_sba_req *)balloc( sizeof(struct sensor_sba_req) * req_num, NULL); if (!reqs) return NULL; info = (struct sensor_sba_info *)balloc(sizeof(struct sensor_sba_info), NULL); if (!info) goto FAIL; info->reqs = reqs; info->bitmap = 0; info->req_cnt = req_num; info->dev_id = dev_id; info->bus_type = bus_type; info->block_type = block_type; for (i = 0; i < req_num; i++) { reqs[i].req.bus_id = bus_id; reqs[i].req.status = 1; if (block_type == SPIN) { reqs[i].req.callback = sensor_bus_callback_spin; reqs[i].complete_flag = 0; } else { reqs[i].req.callback = sensor_bus_callback_sleep; reqs[i].sem = semaphore_create(0); if (!reqs[i].sem) goto FAIL; } reqs[i].req.full_duplex = 0; reqs[i].req.addr.slave_addr = slave_addr; } pr_debug(LOG_MODULE_DRV, "%s: Serial BUS[%d] initialized", __func__, bus_id); return info; FAIL: for (i = 0; i < req_num; i++) { if (reqs[i].sem) { semaphore_delete(reqs[i].sem); reqs[i].sem = NULL; } } if (reqs) bfree(reqs); if (info) bfree(info); pr_debug(LOG_MODULE_DRV, "%s: Serial BUS[%d] init failed", __func__, bus_id); return NULL; }
int websValidateUrl(webs_t wp, char_t *path) { char_t *parts[64]; /* Array of ptr's to URL parts */ char_t *token, *dir, *lpath; int i, len, npart; a_assert(websValid(wp)); a_assert(path); dir = websGetRequestDir(wp); if (dir == NULL || *dir == '\0') { return -1; } /* * Copy the string so we don't destroy the original */ path = bstrdup(B_L, path); websDecodeUrl(path, path, gstrlen(path)); len = npart = 0; parts[0] = NULL; /* * 22 Jul 02 -- there were reports that a directory traversal exploit was * possible in the WebServer running under Windows if directory paths * outside the server's specified root web were given by URL-encoding the * backslash character, like: * * GoAhead is vulnerable to a directory traversal bug. A request such as * * GoAhead-server/../../../../../../../ results in an error message * 'Cannot open URL'. * However, by encoding the '/' character, it is possible to break out of * the * web root and read arbitrary files from the server. * Hence a request like: * * GoAhead-server/..%5C..%5C..%5C..%5C..%5C..%5C/winnt/win.ini returns the * contents of the win.ini file. * (Note that the description uses forward slashes (0x2F), but the example * uses backslashes (0x5C). In my tests, forward slashes are correctly * trapped, but backslashes are not. The code below substitutes forward * slashes for backslashes before attempting to validate that there are no * unauthorized paths being accessed. */ token = gstrchr(path, '\\'); while (token != NULL) { *token = '/'; token = gstrchr(token, '\\'); } token = gstrtok(path, T("/")); /* * Look at each directory segment and process "." and ".." segments * Don't allow the browser to pop outside the root web. */ while (token != NULL) { if (gstrcmp(token, T("..")) == 0) { if (npart > 0) { npart--; } } else if (gstrcmp(token, T(".")) != 0) { parts[npart] = token; len += gstrlen(token) + 1; npart++; } token = gstrtok(NULL, T("/")); } /* * Create local path for document. Need extra space all "/" and null. */ if (npart || (gstrcmp(path, T("/")) == 0) || (path[0] == '\0')) { lpath = balloc(B_L, (gstrlen(dir) + 1 + len + 1) * sizeof(char_t)); gstrcpy(lpath, dir); for (i = 0; i < npart; i++) { gstrcat(lpath, T("/")); gstrcat(lpath, parts[i]); } websSetRequestLpath(wp, lpath); bfree(B_L, path); bfree(B_L, lpath); } else { bfree(B_L, path); return -1; } return 0; }
/* Primary MatrixSSL read function that transparently handles SSL handshakes and the subsequent incoming application data records. A NULL inbuf parameter is an indication that this is a call to perform a new SSL handshake with an incoming client and no out data is expected Params: inbuf allocated storage for plaintext data to be copied to inlen length of inbuf Return codes: -1 EOF or internal failure. caller should free sess and close socket 0 success status. no data is being returned to the caller >0 success status. number of plaintext bytes written to inbuf Note that unlike a standard "socket read", a read of an SSL record can produce data that must be written, for example, a response to a handshake message that must be sent before any more data is read. Also, data can be read from the network such as an SSL alert, that produces no data to pass back to caller. Because webs doesn't have the concept of a read forcing a write, we do the write here, inline. If we are non-blocking, this presents an issue because we can't block indefinitely on a send, and we also can't indicate that the send be done later. The workaround below uses select() to implement a "timed send", which will fail and indicate the connection be closed if not complete within a time threshold. This situation is extremely unlikely in normal operation, since the only records that must be sent as a result of a recv are handshake messages, and TCP buffers would not typically be full enough at that point to result in an EWOULDBLOCK on send. Conceivably, it could occur on a client initiated SSl re-handshake that is sent by a slow-reading client to a server with full TCP buffers. A non-malicious client in this situation would read immediately after a re-handshake request and fail anyway because a buffered appdata record would be read. */ int sslRead(sslConn_t *cp, char *inbuf, int inlen) { unsigned char *buf; int rc, len, transferred; /* Always first look to see if any plaintext application data is waiting We have two levels of buffer here, one for decoded data and one for partial, still encoded SSL records. The partial SSL records are stored transparently in MatrixSSL, but the plaintext is stored in 'cp'. */ if (inbuf != NULL && inlen > 0 && cp->ptBytes > 0 && cp->pt) { if (cp->ptBytes < inlen) { inlen = cp->ptBytes; } memcpy(inbuf, cp->currPt, inlen); cp->currPt += inlen; cp->ptBytes -= inlen; /* Free buffer as we go if empty */ if (cp->ptBytes == 0) { bfree(B_L, cp->pt); cp->pt = cp->currPt = NULL; } return inlen; } /* If there is outgoing data buffered, just try to write it here before doing our read on the socket. Because the read could produce data to be written, this will ensure we have as much room as possible in that case for the written record. Note that there may be data here to send because of a previous sslWrite that got EWOULDBLOCK. */ WRITE_MORE: if ((len = matrixSslGetOutdata(cp->ssl, &buf)) > 0) { transferred = send(cp->fd, buf, len, MSG_NOSIGNAL); if (transferred <= 0) { if (socketGetError() != EWOULDBLOCK) { return -1; } if (waitForWriteEvent(cp->fd, MAX_WRITE_MSEC) == 0) { goto WRITE_MORE; } return -1; } else { /* Indicate that we've written > 0 bytes of data */ if ((rc = matrixSslSentData(cp->ssl, transferred)) < 0) { return -1; } if (rc == MATRIXSSL_REQUEST_CLOSE) { return -1; } else if (rc == MATRIXSSL_HANDSHAKE_COMPLETE) { /* If called via sslAccept (NULL buf), then we can just leave */ return 0; } /* Try to send again if more data to send */ if (rc == MATRIXSSL_REQUEST_SEND || transferred < len) { goto WRITE_MORE; } } } else if (len < 0) { return -1; } READ_MORE: /* Get the ssl buffer and how much data it can accept */ /* Note 0 is a return failure, unlike with matrixSslGetOutdata */ if ((len = matrixSslGetReadbuf(cp->ssl, &buf)) <= 0) { return -1; } if ((transferred = recv(cp->fd, buf, len, MSG_NOSIGNAL)) < 0) { /* Support non-blocking sockets if turned on */ if (socketGetError() == EWOULDBLOCK) { return 0; } trace(1, T("RECV error: %d\n"), socketGetError()); return -1; } if (transferred == 0) { /* If EOF, remote socket closed. This is semi-normal closure. */ trace(4, T("Closing connection %d on EOF\n"), cp->fd); return -1; } /* Notify SSL state machine that we've received more data into the ssl buffer retreived with matrixSslGetReadbuf. */ if ((rc = matrixSslReceivedData(cp->ssl, transferred, &buf, (uint32*)&len)) < 0) { return -1; } PROCESS_MORE: switch (rc) { case MATRIXSSL_REQUEST_SEND: /* There is a handshake response we must send */ goto WRITE_MORE; case MATRIXSSL_REQUEST_RECV: goto READ_MORE; case MATRIXSSL_HANDSHAKE_COMPLETE: /* Session resumption handshake */ goto READ_MORE; case MATRIXSSL_RECEIVED_ALERT: /* Any fatal alert will simply cause a read error and exit */ if (*buf == SSL_ALERT_LEVEL_FATAL) { trace(1, T("Fatal alert: %d, closing connection.\n"), *(buf + 1)); return -1; } /* Closure alert is normal (and best) way to close */ if (*(buf + 1) == SSL_ALERT_CLOSE_NOTIFY) { return -1; } /* Eating warning alerts */ trace(4, T("Warning alert: %d\n"), *(buf + 1)); if ((rc = matrixSslProcessedData(cp->ssl, &buf, (uint32*)&len)) == 0) { /* Possible there was plaintext before the alert */ if (inbuf != NULL && inlen > 0 && cp->ptBytes > 0 && cp->pt) { if (cp->ptBytes < inlen) { inlen = cp->ptBytes; } memcpy(inbuf, cp->currPt, inlen); cp->currPt += inlen; cp->ptBytes -= inlen; /* Free buffer as we go if empty */ if (cp->ptBytes == 0) { bfree(B_L, cp->pt); cp->pt = cp->currPt = NULL; } return inlen; } else { return 0; } } goto PROCESS_MORE; case MATRIXSSL_APP_DATA: if (cp->ptBytes == 0) { /* Catching here means this is new app data just grabbed off the wire. */ cp->ptBytes = len; cp->pt = balloc(B_L, len); memcpy(cp->pt, buf, len); cp->currPt = cp->pt; } else { /* Multi-record. This case should only ever be possible if no data has already been read out of the 'pt' cache so it is fine to assume an unprocessed buffer. */ psAssert(cp->pt == cp->currPt); cp->pt = brealloc(B_L, cp->pt, cp->ptBytes + len); memcpy(cp->pt + cp->ptBytes, buf, len); cp->currPt = cp->pt; cp->ptBytes += len; } if ((rc = matrixSslProcessedData(cp->ssl, &buf, (uint32*)&len)) < 0) { return -1; } /* Check for multi-record app data*/ if (rc > 0) { goto PROCESS_MORE; } /* Otherwise pass back how much the caller wants to read (if any) */ if (inbuf != 0 && inlen > 0) { if (cp->ptBytes < inlen) { inlen = cp->ptBytes; } memcpy(inbuf, cp->currPt, inlen); cp->currPt += inlen; cp->ptBytes -= inlen; return inlen; /* Just a breakpoint holder */ } return 0; /* Have it stored, but caller didn't want any data */ default: return -1; } return 0; /* really can never hit this */ }
char * getHTML() { bstring html = bfromcstr("<!DOCTYPE html>\n<html>\n"); balloc(html, style_css_len); bcatcstr(html, "<head>"); bcatcstr(html, "<title>mdr</title>"); bcatcstr(html, "<style type='text/css'>"); bcatcstr(html, (char *)style_css); bcatcstr(html, "</style>"); bcatcstr(html, "</head>"); bcatcstr(html, "<body>\n<table cellpadding='0'>\n"); // Read from stdin bstring stdinContents = bread ((bNread) fread, stdin); if (stdinContents == NULL) { return "There was an error reading from stdin."; } // Split into lines struct bstrList * inputLines; if ((inputLines = bsplit(stdinContents, '\n')) != NULL) { // We are going to build a map showing which lines in the input belong // in which lines in the output and how they should be displayed. We'll // allocate the left and right maps to be big enough to each hold all // the input data, which is more than enough. lineData * lineMapL = malloc(inputLines->qty * sizeof(lineData)); if (lineMapL == NULL) { free(lineMapL); printf("Memory allocation error.\n"); exit(-1); } lineData * lineMapR = malloc(inputLines->qty * sizeof(lineData)); if (lineMapR == NULL) { free(lineMapR); printf("Memory allocation error.\n"); exit(-1); } int lineMapPosL = 0; int lineMapPosR = 0; int useL; int useR; enum lineType type; int padding; int lineNoL = 0; int lineNoR = 0; int firstInfoLine = TRUE; int startNewFileOk = TRUE; int startOldFileOk = TRUE; // Map input lines to their output column (left, right, or both) int i; for (i = 0; i < inputLines->qty; i++) { useL = 0; useR = 0; type = SHARED; padding = 1; if (startOldFileOk && stringStartsWith(inputLines->entry[i], "---")) { type = OLD_FILE; useL = 1; padding = 4; lineNoL = -1; lineNoR = -1; startOldFileOk = FALSE; } else if (startNewFileOk && stringStartsWith(inputLines->entry[i], "+++")) { type = NEW_FILE; useR = 1; padding = 4; lineNoL = -1; lineNoR = -1; startNewFileOk = FALSE; } else if (stringStartsWith(inputLines->entry[i], "@@")) { syncLineNumbers(inputLines->entry[i], &lineNoL, &lineNoR); if (firstInfoLine) { // Don't print the info row but still increment the line // numbers normally. // TODO: Might be better to mark the row as the first and // hide it with CSS instead of just not printing it. lineNoL++; lineNoR++; } else { type = INFO; useR = 1; useL = 1; padding = 1; } firstInfoLine = FALSE; } else if (bdata(inputLines->entry[i])[0] == '-') { type = OLD; useL = 1; } else if (bdata(inputLines->entry[i])[0] == '+') { type = NEW; useR = 1; } else if (bdata(inputLines->entry[i])[0] == ' ') { type = SHARED; useL = 1; useR = 1; } else { type = HEADER; lineNoL = 0; lineNoR = 0; firstInfoLine = TRUE; startNewFileOk = TRUE; startOldFileOk = TRUE; } // Balance. if (type == HEADER || (type == SHARED && (useL || useR)) || i == inputLines->qty - 1) { int difference = lineMapPosL - lineMapPosR; int j; if (difference > 0) { for (j = 0; j < difference; j++) { lineMapR[lineMapPosR].type = EMPTY; lineMapPosR++; } } else if (difference < 0) { for (j = 0; j < (difference * -1); j++) { lineMapL[lineMapPosL].type = EMPTY; lineMapPosL++; } } } if (useL) { lineMapL[lineMapPosL].inputPos = i; lineMapL[lineMapPosL].type = type; lineMapL[lineMapPosL].padding = padding; lineMapL[lineMapPosL].lineNo = lineNoL - 1; lineMapL[lineMapPosL].leadingSpaces = 0; lineMapPosL++; lineNoL++; } if (useR) { lineMapR[lineMapPosR].inputPos = i; lineMapR[lineMapPosR].type = type; lineMapR[lineMapPosR].padding = padding; lineMapR[lineMapPosR].lineNo = lineNoR - 1; lineMapR[lineMapPosR].leadingSpaces = 0; lineMapPosR++; lineNoR++; } } // Mapping complete. Quick sanity check that both L and R cols have the // same length. if (lineMapPosL != lineMapPosR) { return "Error displaying diff (generated columns not equal in length)."; } // Now we do the formatting work based on the map. for (i = 0; i < lineMapPosL; i++) { int * highlightMaskA = NULL; int * highlightMaskB = NULL; bstring contentL; bstring contentR; int leadingSpacesL = 0; int leadingSpacesR = 0; if (lineMapL[i].type != EMPTY) { contentL = getContentFromLine( inputLines->entry[lineMapL[i].inputPos], lineMapL[i].padding, &leadingSpacesL ); lineMapL[i].leadingSpaces = leadingSpacesL; } if (lineMapR[i].type != EMPTY) { contentR = getContentFromLine( inputLines->entry[lineMapR[i].inputPos], lineMapR[i].padding, &leadingSpacesR ); lineMapR[i].leadingSpaces = leadingSpacesR; } // Compare changed lines if (lineMapL[i].type == OLD && lineMapR[i].type == NEW) { lineMapL[i].type = CHANGE; lineMapR[i].type = CHANGE; determineLineHighlighting( contentL, contentR, &highlightMaskA, &highlightMaskB ); } // Format output bcatcstr(html, "<tr>\n"); if (lineMapL[i].type == EMPTY) { createEmptyLine(html); } else { createLine(LEFT, html, contentL, lineMapL[i], highlightMaskA); bdestroy(contentL); } if (lineMapR[i].type == EMPTY) { createEmptyLine(html); } else { createLine(RIGHT, html, contentR, lineMapR[i], highlightMaskB); bdestroy(contentR); } bcatcstr(html, "</tr>\n"); free(highlightMaskA); free(highlightMaskB); } bcatcstr(html, "</table>\n</body>\n</html>\n"); free(lineMapL); free(lineMapR); } bdestroy(stdinContents); bstrListDestroy(inputLines); char * result = bstr2cstr(html, '-'); bdestroy(html); return result; // Caller should free() }
int socketSelect(int sid, int timeout) { socket_t *sp; struct timeval tv; fd_mask *readFds, *writeFds, *exceptFds; int all, len, nwords, index, bit, nEvents; /* * Allocate and zero the select masks */ nwords = (socketHighestFd + NFDBITS) / NFDBITS; len = nwords * sizeof(int); readFds = balloc(B_L, len); memset(readFds, 0, len); writeFds = balloc(B_L, len); memset(writeFds, 0, len); exceptFds = balloc(B_L, len); memset(exceptFds, 0, len); tv.tv_sec = timeout / 1000; tv.tv_usec = (timeout % 1000) * 1000; /* * Set the select event masks for events to watch */ all = nEvents = 0; if (sid < 0) { all++; sid = 0; } for (; sid < socketMax; sid++) { if ((sp = socketList[sid]) == NULL) { if (all == 0) { break; } else { continue; } } a_assert(sp); /* * Initialize the ready masks and compute the mask offsets. */ index = sp->sock / (NBBY * sizeof(fd_mask)); bit = 1 << (sp->sock % (NBBY * sizeof(fd_mask))); /* * Set the appropriate bit in the ready masks for the sp->sock. */ if (sp->handlerMask & SOCKET_READABLE) { readFds[index] |= bit; nEvents++; if (socketInputBuffered(sid) > 0) { tv.tv_sec = 0; tv.tv_usec = 0; } } if (sp->handlerMask & SOCKET_WRITABLE) { writeFds[index] |= bit; nEvents++; } if (sp->handlerMask & SOCKET_EXCEPTION) { exceptFds[index] |= bit; nEvents++; } if (! all) { break; } } /* * Wait for the event or a timeout. Reset nEvents to be the number of actual * events now. */ nEvents = select(socketHighestFd + 1, (fd_set *) readFds, (fd_set *) writeFds, (fd_set *) exceptFds, &tv); if (nEvents > 0) { if (all) { sid = 0; } for (; sid < socketMax; sid++) { if ((sp = socketList[sid]) == NULL) { if (all == 0) { break; } else { continue; } } index = sp->sock / (NBBY * sizeof(fd_mask)); bit = 1 << (sp->sock % (NBBY * sizeof(fd_mask))); if (readFds[index] & bit || socketInputBuffered(sid) > 0) { sp->currentEvents |= SOCKET_READABLE; } if (writeFds[index] & bit) { sp->currentEvents |= SOCKET_WRITABLE; } if (exceptFds[index] & bit) { sp->currentEvents |= SOCKET_EXCEPTION; } if (! all) { break; } } } bfree(B_L, readFds); bfree(B_L, writeFds); bfree(B_L, exceptFds); return nEvents; }
/* * Process a form request. Returns 1 always to indicate it handled the URL */ int websCgiHandler(webs_t wp, char_t *urlPrefix, char_t *webDir, int arg, char_t *url, char_t *path, char_t* query) { cgiRec *cgip; sym_t *s; char_t cgiBuf[FNAMESIZE], *stdIn, *stdOut, cwd[FNAMESIZE]; char_t *cp, *cgiName, *cgiPath, **argp, **envp, **ep; int n, envpsize, argpsize, pHandle, cid; a_assert(websValid(wp)); a_assert(url && *url); a_assert(path && *path == '/'); websStats.cgiHits++; /* * Extract the form name and then build the full path name. The form * name will follow the first '/' in path. */ gstrncpy(cgiBuf, path, TSZ(cgiBuf)); if ((cgiName = gstrchr(&cgiBuf[1], '/')) == NULL) { websError(wp, 200, T("Missing CGI name")); return 1; } cgiName++; if ((cp = gstrchr(cgiName, '/')) != NULL) { *cp = '\0'; } fmtAlloc(&cgiPath, FNAMESIZE, T("%s/%s/%s"), websGetDefaultDir(), CGI_BIN, cgiName); #ifndef VXWORKS /* * See if the file exists and is executable. If not error out. * Don't do this step for VxWorks, since the module may already * be part of the OS image, rather than in the file system. */ { gstat_t sbuf; if (gstat(cgiPath, &sbuf) != 0 || (sbuf.st_mode & S_IFREG) == 0) { websError(wp, 200, T("CGI process file does not exist")); bfree(B_L, cgiPath); return 1; } #if (defined (WIN) || defined (CE)) if (gstrstr(cgiPath, T(".exe")) == NULL && gstrstr(cgiPath, T(".bat")) == NULL) { #elif (defined (NW)) if (gstrstr(cgiPath, T(".nlm")) == NULL) { #else if (gaccess(cgiPath, X_OK) != 0) { #endif /* WIN || CE */ websError(wp, 200, T("CGI process file is not executable")); bfree(B_L, cgiPath); return 1; } } #endif /* ! VXWORKS */ /* * Get the CWD for resetting after launching the child process CGI */ ggetcwd(cwd, FNAMESIZE); /* * Retrieve the directory of the child process CGI */ if ((cp = gstrrchr(cgiPath, '/')) != NULL) { *cp = '\0'; gchdir(cgiPath); *cp = '/'; } /* * Build command line arguments. Only used if there is no non-encoded * = character. This is indicative of a ISINDEX query. POST separators * are & and others are +. argp will point to a balloc'd array of * pointers. Each pointer will point to substring within the * query string. This array of string pointers is how the spawn or * exec routines expect command line arguments to be passed. Since * we don't know ahead of time how many individual items there are in * the query string, the for loop includes logic to grow the array * size via brealloc. */ argpsize = 10; argp = balloc(B_L, argpsize * sizeof(char_t *)); *argp = cgiPath; n = 1; if (gstrchr(query, '=') == NULL) { websDecodeUrl(query, query, gstrlen(query)); for (cp = gstrtok(query, T(" ")); cp != NULL; ) { *(argp+n) = cp; n++; if (n >= argpsize) { argpsize *= 2; argp = brealloc(B_L, argp, argpsize * sizeof(char_t *)); } cp = gstrtok(NULL, T(" ")); } } *(argp+n) = NULL; /* * Add all CGI variables to the environment strings to be passed * to the spawned CGI process. This includes a few we don't * already have in the symbol table, plus all those that are in * the cgiVars symbol table. envp will point to a balloc'd array of * pointers. Each pointer will point to a balloc'd string containing * the keyword value pair in the form keyword=value. Since we don't * know ahead of time how many environment strings there will be the * for loop includes logic to grow the array size via brealloc. */ envpsize = WEBS_SYM_INIT; envp = balloc(B_L, envpsize * sizeof(char_t *)); n = 0; fmtAlloc(envp+n, FNAMESIZE, T("%s=%s"),T("PATH_TRANSLATED"), cgiPath); n++; fmtAlloc(envp+n, FNAMESIZE, T("%s=%s/%s"),T("SCRIPT_NAME"), CGI_BIN, cgiName); n++; fmtAlloc(envp+n, FNAMESIZE, T("%s=%s"),T("REMOTE_USER"), wp->userName); n++; fmtAlloc(envp+n, FNAMESIZE, T("%s=%s"),T("AUTH_TYPE"), wp->authType); n++; for (s = symFirst(wp->cgiVars); s != NULL; s = symNext(wp->cgiVars)) { if (s->content.valid && s->content.type == string && gstrcmp(s->name.value.string, T("REMOTE_HOST")) != 0 && gstrcmp(s->name.value.string, T("HTTP_AUTHORIZATION")) != 0) { fmtAlloc(envp+n, FNAMESIZE, T("%s=%s"), s->name.value.string, s->content.value.string); n++; if (n >= envpsize) { envpsize *= 2; envp = brealloc(B_L, envp, envpsize * sizeof(char_t *)); } } } if (wp->flags & WEBS_CGI_UPLOAD){ // set filename into enviornment variables fmtAlloc(envp+n, FNAMESIZE, T("%s=%s"), T("UPLOAD_FILENAME"), wp->cgiStdin); n++; } *(envp+n) = NULL; /* * Create temporary file name(s) for the child's stdin and stdout. * For POST data the stdin temp file (and name) should already exist. */ if (wp->cgiStdin == NULL) { wp->cgiStdin = websGetCgiCommName(wp); } stdIn = wp->cgiStdin; stdOut = websGetCgiCommName(wp); /* * Now launch the process. If not successful, do the cleanup of resources. * If successful, the cleanup will be done after the process completes. */ if ((pHandle = websLaunchCgiProc(cgiPath, argp, envp, stdIn, stdOut)) == -1) { websError(wp, 200, T("failed to spawn CGI task")); for (ep = envp; *ep != NULL; ep++) { bfreeSafe(B_L, *ep); } bfreeSafe(B_L, cgiPath); bfreeSafe(B_L, argp); bfreeSafe(B_L, envp); bfreeSafe(B_L, stdOut); } else { /* * If the spawn was successful, put this wp on a queue to be * checked for completion. */ cid = hAllocEntry((void***) &cgiList, &cgiMax, sizeof(cgiRec)); cgip = cgiList[cid]; cgip->handle = pHandle; cgip->stdIn = stdIn; cgip->stdOut = stdOut; cgip->cgiPath = cgiPath; cgip->argp = argp; cgip->envp = envp; cgip->wp = wp; cgip->fplacemark = 0; websTimeoutCancel(wp); } /* * Restore the current working directory after spawning child CGI */ gchdir(cwd); return 1; } /******************************************************************************/ /* * Any entry in the cgiList need to be checked to see if it has */ void websCgiGatherOutput (cgiRec *cgip) { gstat_t sbuf; char_t cgiBuf[FNAMESIZE]; if ((gstat(cgip->stdOut, &sbuf) == 0) && (sbuf.st_size > cgip->fplacemark)) { int fdout; fdout = gopen(cgip->stdOut, O_RDONLY | O_BINARY, 0444 ); /* * Check to see if any data is available in the * output file and send its contents to the socket. */ if (fdout >= 0) { webs_t wp = cgip->wp; int nRead; /* * Write the HTTP header on our first pass */ if (cgip->fplacemark == 0) { websWrite(wp, T("HTTP/1.0 200 OK\r\n")); } glseek(fdout, cgip->fplacemark, SEEK_SET); while ((nRead = gread(fdout, cgiBuf, FNAMESIZE)) > 0) { websWriteBlock(wp, cgiBuf, nRead); cgip->fplacemark += nRead; } gclose(fdout); } } } /******************************************************************************/ /* * Any entry in the cgiList need to be checked to see if it has * completed, and if so, process its output and clean up. */ void websCgiCleanup() { cgiRec *cgip; webs_t wp; char_t **ep; int cid, nTries; for (cid = 0; cid < cgiMax; cid++) { if ((cgip = cgiList[cid]) != NULL) { int exit_status; wp = cgip->wp; websCgiGatherOutput (cgip); if ( websCheckCgiProc(cgip->handle, &exit_status) == 0) { /* * We get here if the CGI process has terminated. Clean up. */ nTries = 0; /* * Make sure we didn't miss something during a task switch. * Maximum wait is 100 times 10 msecs (1 second). */ while ((cgip->fplacemark == 0) && (nTries < 100)) { websCgiGatherOutput(cgip); /* * There are some cases when we detect app exit * before the file is ready. */ if (cgip->fplacemark == 0) { #ifdef WIN Sleep(10); #endif /* WIN*/ } nTries++; } if (cgip->fplacemark == 0) { websError(wp, 200, T("CGI generated no output")); } else { websDone(wp, 200); } /* * Remove the temporary re-direction files */ gunlink(cgip->stdIn); gunlink(cgip->stdOut); /* * Free all the memory buffers pointed to by cgip. * The stdin file name (wp->cgiStdin) gets freed as * part of websFree(). */ cgiMax = hFree((void***) &cgiList, cid); for (ep = cgip->envp; ep != NULL && *ep != NULL; ep++) { bfreeSafe(B_L, *ep); } bfreeSafe(B_L, cgip->cgiPath); bfreeSafe(B_L, cgip->argp); bfreeSafe(B_L, cgip->envp); bfreeSafe(B_L, cgip->stdOut); bfreeSafe(B_L, cgip); #if 0 //DAVIDM - we do not want this, netflash does it for us if(wp->has_firmware_upload_clean){ if (WIFEXITED(exit_status) && WEXITSTATUS(exit_status) != 0) return; sync(); doSystem("sleep 3 && reboot &"); } #endif } } } }
/* ---------------------------------------------------------------------- * my_mkdir: * (1) Allocate INODE space on device using ialloc, which will * return the new directory's inumber * (2) Allocate a block on the device using balloc, which will * return the new directory's block_number * (3) get a newMinode for the new directory using * newdir = iget(dev, inumber) * (4) Setup newdir information * (5) iput(newdir) - release from MINODE table and write to disk * (6) Write . and .. into buf and put the buf to the disk block * (7) Add the name to parent dir * May require "trimming" the length of the last dir entry * in the block. * * To trim, calculate needed_len and ideal_len and trim * the last entry's size to ideal_len * (8) write data back to the disk using put_block(dev, block_number, buf) ------------------------------------------------------------------ */ void my_mkdir(MINODE* pip, char* name) { // (1) pip points to the parent directory, which we'll be adding to int inumber, bnumber; // ino number, blocknumber MINODE* newdir; // directory to be added int i; char* cp; // for iterating through the block DIR* dp; // points to DIR structs within the block int ideallen, neededlen; // ideal_length, needed_length char buf[BLOCK_SIZE]; int dev = pip->dev; // same dev as parent's directory int count = 0; // (2) Allocate inode and a disk block inumber = ialloc(dev); // allocate inumber // Block number will be i_block[0], where this directory's data block begins bnumber = balloc(dev); // allocate blocknumber if (inumber < 1) { printf("my_mkdir() -- ialloc failed with dev %d", dev); } if (bnumber < 1) { printf("my_mkdir() -- balloc failed with dev %d", pip->dev); } // (3) load inode into minode[] in // order to write contents to intended inode in memory newdir = iget(dev, inumber); // (4) Write contents into newdir->INODE newdir->dirty = 1; // Initialize all i_blocks to 0 for (i = 0; i < 15; i++) { newdir->INODE.i_block[i] = 0; } // Directories data blocks start at i_block[0], block number of this directory newdir->INODE.i_block[0] = bnumber; newdir->INODE.i_mode = DIR_MODE; newdir->INODE.i_uid = running->uid; newdir->INODE.i_gid = running->gid; newdir->INODE.i_size = BLOCK_SIZE; // size in bytes newdir->INODE.i_atime = newdir->INODE.i_ctime = newdir->INODE.i_mtime = time(0L); newdir->INODE.i_blocks = 2; // 2-512 bytes newdir->INODE.i_links_count = 2; // (5) write inode to disk iput(newdir); // (6) now write the . and .. entries into a buf[BLOCK_SIZE] // then write buf back to disk block allocated to this directory bzero(buf, BLOCK_SIZE); // clear buf // doing "." dp = (DIR*)buf; // get dir pointer dp->inode = inumber; //inumber = same inumber as new dir strncpy(dp->name, ".", 1); dp->name_len = 1; dp->rec_len = 12; // 8 + multiple of 4 closest and greater than name length // doing ".." dp = (DIR *)(buf + dp->rec_len); dp->inode = pip->ino; // inumber = parent inumber dp->name_len = 2; strncpy(dp->name, "..", 2); dp->rec_len = (BLOCK_SIZE - 12); //take up remainder of block //write block to disk: put_block(dev, bnumber, buf); // (7) Finally, write the directory to it's parent's data blocks //this is the minimum length we need for our new directory /* -------------- NOTES ----------------------------------- * - each EXT2 DIR entry has rec_len and name_len * - the rec_len of the LAST entry in the datablock is to the end of the block * - When entering a new directory with name_len = n * need_length = 4*((8 + name_len + 3)/4) * - Step to the last entry in the data block, it's IDEAL_LENGTH is * IDEAL_LENGTH = 4 *((8 + name_len + 3)/4) * * if(rec_len - IDEAL_LENGTH >= need_length) * Enter new directory as the last entry and trim the * previous entry to its IDEAL_LENGTH * else * allocate a new data block and enter new directory as * first entry in new data block ---------------------------------------------------------------- */ // neededlen = #bytes needed by this new directory neededlen = 4 * ((8 + strlen(name) + 3) / 4); bzero(buf, BLOCK_SIZE); //clear buf // check all the direct blocks for free space for (i = 0; i < 12; i++) { count = 0; // break if the iblock is empty if(pip->INODE.i_block[i] == 0) break; // read parent's data block into buf get_block(dev, pip->INODE.i_block[i], buf); cp = buf; dp = (DIR*) buf; // Step to the last entry of the data block while (cp < &buf[BLOCK_SIZE]) { // ideallen = minimum length that last record takes up? ideallen = 4 * ((8 + dp->name_len + 3) / 4); // calculate ideal length of record (to end of block) if ((dp->rec_len - ideallen) >= neededlen) // There's room in this block { DIR* lastDir; int lastBlockBool; if ((cp + dp->rec_len) < &buf[BLOCK_SIZE]) lastBlockBool = 0; //not the last block else lastBlockBool = 1; //it is the last block! // Trim the length of the last record dp->rec_len = ideallen; //move to beginning of new last entry cp += ideallen; count += ideallen; // add last entry lastDir = (DIR*)cp; lastDir->inode = inumber; lastDir->name_len = strlen(name); strncpy(lastDir->name, name, lastDir->name_len); // If this is the last entry in the data block // it's length extends to the end of the block if (lastBlockBool) lastDir->rec_len = BLOCK_SIZE - count; else lastDir->rec_len = neededlen; // (8) write parent's data block back to disk put_block(dev, pip->INODE.i_block[i], buf); //update parent inode link count pip->INODE.i_links_count++; pip->INODE.i_atime = time(0L); pip->dirty = 1; iput(pip); // Write back to disk // Update group descriptor free_inodes and such updateGD(); return; } //advance dp to next dir entry in it's block: count += dp->rec_len; cp += dp->rec_len; dp = (DIR*) cp; } } return; }
void* AllocateExecutableMemory(size_t size, bool low) { #ifdef _XBOX void* ptr = balloc(size); #elif defined(_WIN32) void* ptr = VirtualAlloc(0, size, MEM_COMMIT, PAGE_EXECUTE_READWRITE); #elif defined(__SYMBIAN32__) //This function may be called more than once, and we want to create only one big //memory chunk for all the executable code for the JIT if( g_code_chunk == NULL && g_code_heap == NULL) { g_code_chunk = new RChunk(); g_code_chunk->CreateLocalCode(CODECHUNK_SIZE, CODECHUNK_SIZE + 3*GetPageSize()); g_code_heap = UserHeap::ChunkHeap(*g_code_chunk, CODECHUNK_SIZE, 1, CODECHUNK_SIZE + 3*GetPageSize()); g_next_ptr = reinterpret_cast<u8*>(g_code_heap->AllocZ(CODECHUNK_SIZE)); g_orig_ptr = g_next_ptr; } void* ptr = (void*)g_next_ptr; g_next_ptr += size; #else static char *map_hint = 0; #if defined(__x86_64__) && !defined(MAP_32BIT) // This OS has no flag to enforce allocation below the 4 GB boundary, // but if we hint that we want a low address it is very likely we will // get one. // An older version of this code used MAP_FIXED, but that has the side // effect of discarding already mapped pages that happen to be in the // requested virtual memory range (such as the emulated RAM, sometimes). if (low && (!map_hint)) map_hint = (char*)round_page(512*1024*1024); /* 0.5 GB rounded up to the next page */ #endif void* ptr = mmap(map_hint, size, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_ANON | MAP_PRIVATE #if defined(__x86_64__) && defined(MAP_32BIT) | (low ? MAP_32BIT : 0) #endif , -1, 0); #endif /* defined(_WIN32) */ // printf("Mapped executable memory at %p (size %ld)\n", ptr, // (unsigned long)size); #if defined(__FreeBSD__) if (ptr == MAP_FAILED) { ptr = NULL; #else if (ptr == NULL) { #endif PanicAlert("Failed to allocate executable memory"); } #if !defined(_WIN32) && defined(__x86_64__) && !defined(MAP_32BIT) else if (low) { map_hint += size; map_hint = (char*)round_page(map_hint); /* round up to the next page */ // printf("Next map will (hopefully) be at %p\n", map_hint); } #endif return ptr; } void* AllocateMemoryPages(size_t size) { size = (size + 4095) & (~4095); #ifdef _WIN32 void* ptr = VirtualAlloc(0, size, MEM_COMMIT, PAGE_READWRITE); #elif defined(__SYMBIAN32__) void* ptr = malloc(size); #else void* ptr = mmap(0, size, PROT_READ | PROT_WRITE, MAP_ANON | MAP_PRIVATE, -1, 0); #endif // printf("Mapped memory at %p (size %ld)\n", ptr, // (unsigned long)size); if (ptr == NULL) PanicAlert("Failed to allocate raw memory"); return ptr; }
static void remote_send_cb(EV_P_ ev_io *w, int revents) { remote_ctx_t *remote_send_ctx = (remote_ctx_t *)w; remote_t *remote = remote_send_ctx->remote; server_t *server = remote->server; ev_timer_stop(EV_A_ & remote_send_ctx->watcher); if (!remote_send_ctx->connected) { int r = 0; if (remote->addr == NULL) { struct sockaddr_storage addr; memset(&addr, 0, sizeof(struct sockaddr_storage)); socklen_t len = sizeof addr; r = getpeername(remote->fd, (struct sockaddr *)&addr, &len); } if (r == 0) { remote_send_ctx->connected = 1; ev_io_stop(EV_A_ & remote_send_ctx->io); ev_io_stop(EV_A_ & server->recv_ctx->io); ev_io_start(EV_A_ & remote->recv_ctx->io); ev_timer_start(EV_A_ & remote->recv_ctx->watcher); // send destaddr buffer_t ss_addr_to_send; buffer_t *abuf = &ss_addr_to_send; balloc(abuf, BUF_SIZE); if (server->hostname_len > 0 && validate_hostname(server->hostname, server->hostname_len)) { // HTTP/SNI uint16_t port; if (AF_INET6 == server->destaddr.ss_family) { // IPv6 port = (((struct sockaddr_in6 *)&(server->destaddr))->sin6_port); } else { // IPv4 port = (((struct sockaddr_in *)&(server->destaddr))->sin_port); } abuf->data[abuf->len++] = 3; // Type 3 is hostname abuf->data[abuf->len++] = server->hostname_len; memcpy(abuf->data + abuf->len, server->hostname, server->hostname_len); abuf->len += server->hostname_len; memcpy(abuf->data + abuf->len, &port, 2); } else if (AF_INET6 == server->destaddr.ss_family) { // IPv6 abuf->data[abuf->len++] = 4; // Type 4 is IPv6 address size_t in6_addr_len = sizeof(struct in6_addr); memcpy(abuf->data + abuf->len, &(((struct sockaddr_in6 *)&(server->destaddr))->sin6_addr), in6_addr_len); abuf->len += in6_addr_len; memcpy(abuf->data + abuf->len, &(((struct sockaddr_in6 *)&(server->destaddr))->sin6_port), 2); } else { // IPv4 abuf->data[abuf->len++] = 1; // Type 1 is IPv4 address size_t in_addr_len = sizeof(struct in_addr); memcpy(abuf->data + abuf->len, &((struct sockaddr_in *)&(server->destaddr))->sin_addr, in_addr_len); abuf->len += in_addr_len; memcpy(abuf->data + abuf->len, &((struct sockaddr_in *)&(server->destaddr))->sin_port, 2); } abuf->len += 2; int err = crypto->encrypt(abuf, server->e_ctx, BUF_SIZE); if (err) { LOGE("invalid password or cipher"); bfree(abuf); close_and_free_remote(EV_A_ remote); close_and_free_server(EV_A_ server); return; } err = crypto->encrypt(remote->buf, server->e_ctx, BUF_SIZE); if (err) { LOGE("invalid password or cipher"); bfree(abuf); close_and_free_remote(EV_A_ remote); close_and_free_server(EV_A_ server); return; } bprepend(remote->buf, abuf, BUF_SIZE); bfree(abuf); } else { ERROR("getpeername"); // not connected close_and_free_remote(EV_A_ remote); close_and_free_server(EV_A_ server); return; } } if (remote->buf->len == 0) { // close and free close_and_free_remote(EV_A_ remote); close_and_free_server(EV_A_ server); return; } else { // has data to send ssize_t s; if (remote->addr != NULL) { s = sendto(remote->fd, remote->buf->data + remote->buf->idx, remote->buf->len, MSG_FASTOPEN, remote->addr, get_sockaddr_len(remote->addr)); if (s == -1 && (errno == EOPNOTSUPP || errno == EPROTONOSUPPORT || errno == ENOPROTOOPT)) { fast_open = 0; LOGE("fast open is not supported on this platform"); close_and_free_remote(EV_A_ remote); close_and_free_server(EV_A_ server); return; } remote->addr = NULL; if (s == -1) { if (errno == CONNECT_IN_PROGRESS || errno == EAGAIN || errno == EWOULDBLOCK) { ev_io_start(EV_A_ & remote_send_ctx->io); ev_timer_start(EV_A_ & remote_send_ctx->watcher); } else { ERROR("connect"); close_and_free_remote(EV_A_ remote); close_and_free_server(EV_A_ server); } return; } } else { s = send(remote->fd, remote->buf->data + remote->buf->idx, remote->buf->len, 0); } if (s == -1) { if (errno != EAGAIN && errno != EWOULDBLOCK) { ERROR("send"); // close and free close_and_free_remote(EV_A_ remote); close_and_free_server(EV_A_ server); } return; } else if (s < remote->buf->len) { // partly sent, move memory, wait for the next time to send remote->buf->len -= s; remote->buf->idx += s; ev_io_start(EV_A_ & remote_send_ctx->io); return; } else { // all sent out, wait for reading remote->buf->len = 0; remote->buf->idx = 0; ev_io_stop(EV_A_ & remote_send_ctx->io); ev_io_start(EV_A_ & server->recv_ctx->io); } } }
int websAspRequest(webs_t wp, char_t *lpath) { websStatType sbuf; char *rbuf; char_t *token, *lang, *result, *path, *ep, *cp, *buf, *nextp; char_t *last; int rc, engine, len, ejid; a_assert(websValid(wp)); a_assert(lpath && *lpath); rc = -1; buf = NULL; rbuf = NULL; engine = EMF_SCRIPT_EJSCRIPT; wp->flags |= WEBS_HEADER_DONE; path = websGetRequestPath(wp); /* * Create Ejscript instance in case it is needed */ ejid = ejOpenEngine(wp->cgiVars, websAspFunctions); if (ejid < 0) { websError(wp, 200, T("Can't create Ejscript engine")); goto done; } ejSetUserHandle(ejid, (int) wp); if (websPageStat(wp, lpath, path, &sbuf) < 0) { websError(wp, 200, T("Can't stat %s"), lpath); goto done; } /* * Create a buffer to hold the ASP file in-memory */ len = sbuf.size * sizeof(char); if ((rbuf = balloc(B_L, len + 1)) == NULL) { websError(wp, 200, T("Can't get memory")); goto done; } rbuf[len] = '\0'; if (websPageReadData(wp, rbuf, len) != len) { websError(wp, 200, T("Cant read %s"), lpath); goto done; } websPageClose(wp); /* * Convert to UNICODE if necessary. */ if ((buf = ballocAscToUni(rbuf, len)) == NULL) { websError(wp, 200, T("Can't get memory")); goto done; } /* * Scan for the next "<%" */ last = buf; rc = 0; while (rc == 0 && *last && ((nextp = gstrstr(last, T("<%"))) != NULL)) { websWriteBlock(wp, last, (nextp - last)); nextp = skipWhite(nextp + 2); /* * Decode the language */ token = T("language"); if ((lang = strtokcmp(nextp, token)) != NULL) { if ((cp = strtokcmp(lang, T("=javascript"))) != NULL) { engine = EMF_SCRIPT_EJSCRIPT; } else { cp = nextp; } nextp = cp; } /* * Find tailing bracket and then evaluate the script */ if ((ep = gstrstr(nextp, T("%>"))) != NULL) { *ep = '\0'; last = ep + 2; nextp = skipWhite(nextp); /* * Handle backquoted newlines */ for (cp = nextp; *cp; ) { if (*cp == '\\' && (cp[1] == '\r' || cp[1] == '\n')) { *cp++ = ' '; while (*cp == '\r' || *cp == '\n') { *cp++ = ' '; } } else { cp++; } } /* * Now call the relevant script engine. Output is done directly * by the ASP script procedure by calling websWrite() */ if (*nextp) { result = NULL; if (engine == EMF_SCRIPT_EJSCRIPT) { rc = scriptEval(engine, nextp, &result, ejid); } else { rc = scriptEval(engine, nextp, &result, (int) wp); } if (rc < 0) { /* * On an error, discard all output accumulated so far * and store the error in the result buffer. Be careful if the * user has called websError() already. */ if (websValid(wp)) { if (result) { websWrite(wp, T("<h2><b>ASP Error: %s</b></h2>\n"), result); websWrite(wp, T("<pre>%s</pre>"), nextp); bfree(B_L, result); } else { websWrite(wp, T("<h2><b>ASP Error</b></h2>\n%s\n"), nextp); } websWrite(wp, T("</body></html>\n")); rc = 0; } goto done; } } } else { websError(wp, 200, T("Unterminated script in %s: \n"), lpath); rc = -1; goto done; } } /* * Output any trailing HTML page text */ if (last && *last && rc == 0) { websWriteBlock(wp, last, gstrlen(last)); } rc = 0; /* * Common exit and cleanup */ done: if (websValid(wp)) { websPageClose(wp); if (ejid >= 0) { ejCloseEngine(ejid); } } bfreeSafe(B_L, buf); bfreeSafe(B_L, rbuf); return rc; }
int websUrlParse(char_t *url, char_t **pbuf, char_t **phost, char_t **ppath, char_t **pport, char_t **pquery, char_t **pproto, char_t **ptag, char_t **pext) { char_t *tok, *cp, *host, *path, *port, *proto, *tag, *query, *ext; char_t *last_delim, *hostbuf, *portbuf, *buf; int c, len, ulen; a_assert(url); a_assert(pbuf); ulen = gstrlen(url); /* * We allocate enough to store separate hostname and port number fields. * As there are 3 strings in the one buffer, we need room for 3 null chars. * We allocate MAX_PORT_LEN char_t's for the port number. */ len = ulen * 2 + MAX_PORT_LEN + 3; if ((buf = balloc(B_L, len * sizeof(char_t))) == NULL) { return -1; } portbuf = &buf[len - MAX_PORT_LEN - 1]; hostbuf = &buf[ulen+1]; gstrcpy(buf, url); url = buf; /* * Convert the current listen port to a string. We use this if the URL has * no explicit port setting */ stritoa(websGetPort(), portbuf, MAX_PORT_LEN); port = portbuf; path = T("/"); proto = T("http"); host = T("localhost"); query = T(""); ext = htmExt; tag = T(""); if (gstrncmp(url, T("http://"), 7) == 0) { tok = &url[7]; tok[-3] = '\0'; proto = url; host = tok; for (cp = tok; *cp; cp++) { if (*cp == '/') { break; } if (*cp == ':') { *cp++ = '\0'; port = cp; tok = cp; } } if ((cp = gstrchr(tok, '/')) != NULL) { /* * If a full URL is supplied, we need to copy the host and port * portions into static buffers. */ c = *cp; *cp = '\0'; gstrncpy(hostbuf, host, ulen); gstrncpy(portbuf, port, MAX_PORT_LEN); *cp = c; host = hostbuf; port = portbuf; path = cp; tok = cp; } } else { path = url; tok = url; } /* * Parse the query string */ if ((cp = gstrchr(tok, '?')) != NULL) { *cp++ = '\0'; query = cp; path = tok; tok = query; } /* * Parse the fragment identifier */ if ((cp = gstrchr(tok, '#')) != NULL) { *cp++ = '\0'; if (*query == 0) { path = tok; } } /* * Only do the following if asked for the extension */ if (pext) { if ((cp = gstrrchr(path, '.')) != NULL) { if ((last_delim = gstrrchr(path, '/')) != NULL) { if (last_delim > cp) { ext = htmExt; } else { ext = cp; } } else { ext = cp; } } else { if (path[gstrlen(path) - 1] == '/') { ext = htmExt; } } } /* * Pass back the fields requested (if not NULL) */ if (phost) *phost = host; if (ppath) *ppath = path; if (pport) *pport = port; if (pproto) *pproto = proto; if (pquery) *pquery = query; if (ptag) *ptag = tag; if (pext) *pext = ext; *pbuf = buf; return 0; }
void eval_jerry_script (int argc, char *argv[], struct tcmd_handler_ctx *ctx) { if (argc < 3) { TCMD_RSP_ERROR (ctx, NULL); help (); return; } else { OS_ERR_TYPE err; size_t str_total_length = 0; size_t *str_lens = (size_t *) balloc ((argc - 2) * sizeof(size_t), &err); if (str_lens == NULL || err != E_OS_OK) { printk ("%s: allocate memory failed!", __func__); TCMD_RSP_ERROR (ctx, NULL); return; } for (int i = 2; i < argc; ++i) { str_lens[i - 2] = strlen (argv[i]); str_total_length += str_lens[i - 2] + 1; } err = E_OS_OK; char *buffer = (char *) balloc (str_total_length, &err); if (buffer == NULL || err != E_OS_OK) { printk ("%s: allocate memory failed!", __func__); TCMD_RSP_ERROR (ctx, NULL); return; } char *p = buffer; for (int i = 2; i < argc; ++i) { for (int j =0; j < str_lens[i - 2]; ++j) { *p = argv[i][j]; ++p; } *p = ' '; ++p; } *p = '\0'; jerry_value_t eval_ret = jerry_eval (buffer, str_total_length - 1, false); if (jerry_value_is_error (eval_ret)) { jerry_resolve_error (eval_ret); TCMD_RSP_ERROR (ctx, NULL); } else { jerry_value_t args[] = {eval_ret}; jerry_value_t ret_val_print = jerry_call_function (print_function, jerry_create_undefined (), args, 1); jerry_release_value (ret_val_print); TCMD_RSP_FINAL (ctx, NULL); } jerry_release_value (eval_ret); bfree (buffer); bfree (str_lens); } }
int mkfile(char * filename,struct m_inode* inode)// inode为待添加文件的目录的主存索引节点 { if(inode==NULL) return -1; if(inode->finode.mode!=1) { cout<<"非目录文件"<<endl; return -1; } int count=inode->finode.fileSize/sizeof(struct direct); if(count>ADDRN*DIRNUM) { cout<<"目录项已最大"<<endl; return -1; } dir * dir=(struct dir*)calloc(1,sizeof(struct dir)); for(int addr=0; addr<inode->finode.addrnum; addr++) { bread(dir,inode->finode.addr[addr],0,sizeof(struct dir),1); for(int i=0; i<dir->dirNum; i++) if(strcmp(dir->direct[i].directName,filename)==0) { cout.write(filename,strlen(filename)); cout<<"目录项已存在"<<endl; return -1; } } bread(dir,inode->finode.addr[inode->finode.addrnum-1],0,sizeof(struct dir),1);//读出最后一个数据块的目录 struct m_inode * tmpinode=ialloc();//分配子目录I节点 tmpinode->finode.addr[0]=balloc();//分配子目录磁盘块 tmpinode->finode.mode=0; write_finode(tmpinode); if(dir->dirNum==DIRNUM)//当前数据块可容纳目录已满,再申请数据块 { inode->finode.addr[inode->finode.addrnum]=balloc(); memset(dir,0,sizeof(struct dir)); strcpy(dir->direct[0].directName,filename);//修改目录 dir->direct[0].inodeID=tmpinode->inodeID; dir->dirNum=1; bwrite(dir,inode->finode.addr[inode->finode.addrnum],0,sizeof(struct dir),1); inode->finode.addrnum++; inode->finode.fileSize+=sizeof(struct direct);//更新inodeI节点 write_finode(inode); return 1; } else { strcpy(dir->direct[dir->dirNum].directName,filename);//修改目录目录项 dir->direct[dir->dirNum].inodeID=tmpinode->inodeID; dir->dirNum+=1; bwrite(dir,inode->finode.addr[inode->finode.addrnum-1],0,sizeof(struct dir),1); inode->finode.fileSize+=sizeof(struct direct);//更新I节点 write_finode(inode); return 1; } }
static const char *parse_string(opstack ** stack, const char *in, const void *userdata) { /* (char*) -> char* */ char *c; char *buffer = balloc(TOKENSIZE); size_t size = TOKENSIZE - 1; const char *ic = in; char *oc = buffer; /* mode flags */ bool f_escape = false; bool bDone = false; variant var; while (*ic && !bDone) { if (f_escape) { f_escape = false; switch (*ic) { case 'n': if (size > 0) { *oc++ = '\n'; --size; } break; case 't': if (size > 0) { *oc++ = '\t'; --size; } break; default: if (size > 0) { *oc++ = *ic++; --size; } } } else { int ch = (unsigned char)(*ic); size_t bytes; switch (ch) { case '\\': f_escape = true; ++ic; break; case '"': bDone = true; ++ic; break; case '$': ic = parse_symbol(stack, ++ic, userdata); if (ic == NULL) return NULL; c = (char *)opop_v(stack); bytes = (c ? strlcpy(oc, c, size) : 0); if (bytes < size) oc += bytes; else oc += size; bfree(c); break; default: if (size > 0) { *oc++ = *ic++; --size; } else ++ic; } } } *oc++ = '\0'; bfree(oc); var.v = buffer; opush(stack, var); return ic; }
int websValidateUrl(webs_t wp, char_t *path) { /* Thanks to Dhanwa T ([email protected]) for this fix -- previously, if an URL was requested having more than (the hardcoded) 64 parts, the webServer would experience a hard crash as it attempted to write past the end of the array 'parts'. Also fixes: http://www.securiteam.com/securitynews/5MP0C1580W.html */ char_t *parts[MAX_URL_DEPTH]; /* Array of ptr's to URL parts */ char_t *token, *dir, *lpath; int i, len, npart; a_assert(websValid(wp)); a_assert(path); dir = websGetRequestDir(wp); if (dir == NULL || *dir == '\0') { return -1; } /* * Copy the string so we don't destroy the original */ path = bstrdup(B_L, path); websDecodeUrl(path, path, gstrlen(path)); len = npart = 0; parts[0] = NULL; /* * Fixed by Matt Moore, 22 Jul 02 * http://www.securiteam.com/securitynews/5RP0I007PG.html * http://www.securiteam.com/securitynews/5QP010U3FS.html * * There were reports that a directory traversal exploit was * possible in the WebServer running under Windows if directory paths * outside the server's specified root web were given by URL-encoding the * backslash character, like: * * GoAhead is vulnerable to a directory traversal bug. A request such as * * GoAhead-server/../../../../../../../ results in an error message * 'Cannot open URL'. * However, by encoding the '/' character, it is possible to break out of * the web root and read arbitrary files from the server. * Hence a request like: * * GoAhead-server/..%5C..%5C..%5C..%5C..%5C..%5C/winnt/win.ini returns the * contents of the win.ini file. * (Note that the description uses forward slashes (0x2F), but the example * uses backslashes (0x5C). In my tests, forward slashes are correctly * trapped, but backslashes are not. The code below substitutes forward * slashes for backslashes before attempting to validate that there are no * unauthorized paths being accessed. */ token = gstrchr(path, '\\'); while (token != NULL) { *token = '/'; token = gstrchr(token, '\\'); } token = gstrtok(path, T("/")); /* * Look at each directory segment and process "." and ".." segments * Don't allow the browser to pop outside the root web. */ while (token != NULL) { if (npart >= MAX_URL_DEPTH) { /* * malformed URL -- too many parts for us to process. */ bfree(B_L, path); return -1; } if (gstrcmp(token, T("..")) == 0) { if (npart > 0) { npart--; } } else if (gstrcmp(token, T(".")) != 0) { parts[npart] = token; len += gstrlen(token) + 1; npart++; } token = gstrtok(NULL, T("/")); } #ifdef WIN32 if (isBadWindowsPath(parts, npart)) { bfree(B_L, path); return -1; } #endif /* * Create local path for document. Need extra space all "/" and null. */ if (npart || (gstrcmp(path, T("/")) == 0) || (path[0] == '\0')) { lpath = balloc(B_L, (gstrlen(dir) + 1 + len + 1) * sizeof(char_t)); gstrcpy(lpath, dir); for (i = 0; i < npart; i++) { gstrcat(lpath, T("/")); gstrcat(lpath, parts[i]); } websSetRequestLpath(wp, lpath); bfree(B_L, path); bfree(B_L, lpath); } else { bfree(B_L, path); return -1; } return 0; }
int main(int argc, char *argv[]) { int i, cc, fd; uint rootino, inum, off; struct dirent de; char buf[BSIZE]; struct dinode din; static_assert(sizeof(int) == 4, "Integers must be 4 bytes!"); if(argc < 2){ fprintf(stderr, "Usage: mkfs fs.img files...\n"); exit(1); } assert((BSIZE % sizeof(struct dinode)) == 0); assert((BSIZE % sizeof(struct dirent)) == 0); fsfd = open(argv[1], O_RDWR|O_CREAT|O_TRUNC, 0666); if(fsfd < 0){ perror(argv[1]); exit(1); } // 1 fs block = 1 disk sector nmeta = 2 + nlog + ninodeblocks + nbitmap; nblocks = FSSIZE - nmeta; sb.size = xint(FSSIZE); sb.nblocks = xint(nblocks); sb.ninodes = xint(NINODES); sb.nlog = xint(nlog); sb.logstart = xint(2); sb.inodestart = xint(2+nlog); sb.bmapstart = xint(2+nlog+ninodeblocks); printf("nmeta %d (boot, super, log blocks %u inode blocks %u, bitmap blocks %u) blocks %d total %d\n", nmeta, nlog, ninodeblocks, nbitmap, nblocks, FSSIZE); freeblock = nmeta; // the first free block that we can allocate for(i = 0; i < FSSIZE; i++) wsect(i, zeroes); memset(buf, 0, sizeof(buf)); memmove(buf, &sb, sizeof(sb)); wsect(1, buf); rootino = ialloc(T_DIR); assert(rootino == ROOTINO); bzero(&de, sizeof(de)); de.inum = xshort(rootino); strcpy(de.name, "."); iappend(rootino, &de, sizeof(de)); bzero(&de, sizeof(de)); de.inum = xshort(rootino); strcpy(de.name, ".."); iappend(rootino, &de, sizeof(de)); for(i = 2; i < argc; i++){ assert(index(argv[i], '/') == 0); if((fd = open(argv[i], 0)) < 0){ perror(argv[i]); exit(1); } // Skip leading _ in name when writing to file system. // The binaries are named _rm, _cat, etc. to keep the // build operating system from trying to execute them // in place of system binaries like rm and cat. if(argv[i][0] == '_') ++argv[i]; inum = ialloc(T_FILE); bzero(&de, sizeof(de)); de.inum = xshort(inum); strncpy(de.name, argv[i], DIRSIZ); iappend(rootino, &de, sizeof(de)); while((cc = read(fd, buf, sizeof(buf))) > 0) iappend(inum, buf, cc); close(fd); } // fix size of root inode dir rinode(rootino, &din); off = xint(din.size); off = ((off/BSIZE) + 1) * BSIZE; din.size = xint(off); winode(rootino, &din); balloc(freeblock); exit(0); }
static int websBuildWhitelistRecursive(char *_path, fileNode_t *dir, int level) { WIN32_FIND_DATA findData; HANDLE fh; fileNode_t *cnode, *nnode; /* current node, next node */ #ifdef WEBS_SSL_SUPPORT sslList_t *l; #endif int rc = 0; int firstTime; char path[MAX_PATH]; char tmppath[MAX_PATH]; firstTime = 1; cnode = dir; websMakePath(path, _path, NULL, 1); fh = FindFirstFile((LPCSTR)path, &findData); while (fh != INVALID_HANDLE_VALUE) { if ((strcmp(findData.cFileName, ".") == 0) || (strcmp(findData.cFileName, "..") == 0) || (findData.dwFileAttributes & FILE_ATTRIBUTE_HIDDEN) || (findData.dwFileAttributes & FILE_ATTRIBUTE_SYSTEM)) { goto nextFile; } nnode = balloc(B_L, sizeof(fileNode_t)); memset(nnode, 0x0, sizeof(fileNode_t)); if (findData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) { fmtAlloc(&(nnode->name), MAX_PATH, "%s/", findData.cFileName); nnode->flags |= WHITELIST_DIR; } else { nnode->name = bstrdup(B_L, findData.cFileName); } if (firstTime) { cnode->child = nnode; firstTime = 0; } else { cnode->next = nnode; } cnode = nnode; if (strncmp(path + strlen(websDefaultDir), "/" CGI_BIN, strlen(CGI_BIN) + 1) == 0) { cnode->flags |= WHITELIST_CGI; } #ifdef WEBS_SSL_SUPPORT for (l = sslList; l != NULL; l = l->next) { if (strncmp(path + strlen(websDefaultDir), l->url, strlen(l->url)) == 0) { cnode->flags |= WHITELIST_SSL; } } #endif /* WEBS_SSL_SUPPORT */ if (findData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) { websMakePath(tmppath, path, findData.cFileName, 1); if (level < MAX_URL_DEPTH) { if (websBuildWhitelistRecursive(tmppath, cnode, level + 1) < 0){ cnode->flags |= WHITELIST_BLOCKED; } } } nextFile: if (FindNextFile(fh, &findData) == 0) { if (GetLastError() != ERROR_NO_MORE_FILES) { rc = -1; } break; } } FindClose(fh); return rc; }
int main(int argc, char *argv[]) { int i, cc, fd; uint rootino, inum, off; struct dirent de; char buf[512]; struct dinode din; static_assert(sizeof(int) == 4, "Integers must be 4 bytes!"); if(argc < 2){ fprintf(stderr, "Usage: mkfs fs.img files...\n"); exit(1); } assert((512 % sizeof(struct dinode)) == 0); assert((512 % sizeof(struct dirent)) == 0); fsfd = open(argv[1], O_RDWR|O_CREAT|O_TRUNC, 0666); if(fsfd < 0){ perror(argv[1]); exit(1); } sb.size = xint(size); sb.nblocks = xint(nblocks); // so whole disk is size sectors sb.ninodes = xint(ninodes); sb.nlog = xint(nlog); bitblocks = size/(512*8) + 1; usedblocks = ninodes / IPB + 3 + bitblocks; freeblock = usedblocks; printf("used %d (bit %d ninode %zu) free %u log %u total %d\n", usedblocks, bitblocks, ninodes/IPB + 1, freeblock, nlog, nblocks+usedblocks+nlog); assert(nblocks + usedblocks + nlog == size); for(i = 0; i < nblocks + usedblocks + nlog; i++) wsect(i, zeroes); memset(buf, 0, sizeof(buf)); memmove(buf, &sb, sizeof(sb)); wsect(1, buf); rootino = ialloc(T_DIR); assert(rootino == ROOTINO); bzero(&de, sizeof(de)); de.inum = xshort(rootino); strcpy(de.name, "."); iappend(rootino, &de, sizeof(de)); bzero(&de, sizeof(de)); de.inum = xshort(rootino); strcpy(de.name, ".."); iappend(rootino, &de, sizeof(de)); for(i = 2; i < argc; i++){ char *name = argv[i]; if (!strncmp(name, "fs/", 3)) name += 3; assert(index(name, '/') == 0); if((fd = open(argv[i], 0)) < 0){ perror(argv[i]); exit(1); } inum = ialloc(T_FILE); bzero(&de, sizeof(de)); de.inum = xshort(inum); strncpy(de.name, name, DIRSIZ); iappend(rootino, &de, sizeof(de)); while((cc = read(fd, buf, sizeof(buf))) > 0) iappend(inum, buf, cc); close(fd); } // fix size of root inode dir rinode(rootino, &din); off = xint(din.size); off = ((off/BSIZE) + 1) * BSIZE; din.size = xint(off); winode(rootino, &din); balloc(usedblocks); exit(0); }
/* * LINUX, MACOSX, ETC: Build whitelist */ #else /* !WIN */ static int websBuildWhitelistRecursive(char *_path, fileNode_t *dir, int level) { struct dirent *findData, *result; DIR *fh; fileNode_t *cnode, *nnode; /* current node, next node */ int firstTime; char path[PATH_MAX]; char tmppath[PATH_MAX]; firstTime = 1; cnode = dir; /* On some platforms such as Solaris, struct dirent includes only one * byte for d_name field, meaning we would overflow the field when * readdir_r is called. So we check for this here. * Another potential issue is if somehow a filesystem is mounted or linked * in a subdirectory or file that has name longer than PATH_MAX. We * ignore that possibility here, and leave it to the user to ensure that * the wwwroot directory does not contain this configuration. * http://womble.decadentplace.org.uk/readdir_r-advisory.html */ if (sizeof(struct dirent) > PATH_MAX) { findData = balloc(B_L, sizeof(struct dirent)); } else { findData = balloc(B_L, sizeof(struct dirent) + PATH_MAX); } websMakePath(path, _path, NULL, 0); if ((fh = opendir(path)) == NULL) { bfree(B_L, findData); return -1; /* Likely no permission to access this directory */ } while ((readdir_r(fh, findData, &result) == 0) && result) { if ((strcmp(findData->d_name, ".") == 0) || (strcmp(findData->d_name, "..") == 0) || (findData->d_type != DT_REG && findData->d_type != DT_DIR)) { continue; } nnode = balloc(B_L, sizeof(fileNode_t)); memset(nnode, 0x0, sizeof(fileNode_t)); if (findData->d_type == DT_DIR) { fmtAlloc(&(nnode->name), PATH_MAX, "%s/", findData->d_name); nnode->flags |= WHITELIST_DIR; } else { nnode->name = bstrdup(B_L, findData->d_name); } if (firstTime) { cnode->child = nnode; firstTime = 0; } else { cnode->next = nnode; } cnode = nnode; if (strncmp(path + strlen(websDefaultDir), "/" CGI_BIN, strlen(CGI_BIN) + 1) == 0) { cnode->flags |= WHITELIST_CGI; } #ifdef WEBS_SSL_SUPPORT sslList_t *l; for (l = sslList; l != NULL; l = l->next) { if (strncmp(path + strlen(websDefaultDir), l->url, strlen(l->url)) == 0) { cnode->flags |= WHITELIST_SSL; break; } } #endif /* WEBS_SSL_SUPPORT */ if (findData->d_type == DT_DIR) { websMakePath(tmppath, path, findData->d_name, 0); if (level < MAX_URL_DEPTH) { if (websBuildWhitelistRecursive(tmppath, cnode, level + 1) < 0){ cnode->flags |= WHITELIST_BLOCKED; } } } } bfree(B_L, findData); closedir(fh); return 0; }
static void remote_recv_cb(EV_P_ ev_io *w, int revents) { ssize_t r; remote_ctx_t *remote_ctx = (remote_ctx_t *)w; server_ctx_t *server_ctx = remote_ctx->server_ctx; // server has been closed if (server_ctx == NULL) { LOGE("[udp] invalid server"); close_and_free_remote(EV_A_ remote_ctx); return; } if (verbose) { LOGI("[udp] remote receive a packet"); } struct sockaddr_storage src_addr; socklen_t src_addr_len = sizeof(struct sockaddr_storage); memset(&src_addr, 0, src_addr_len); buffer_t *buf = ss_malloc(sizeof(buffer_t)); balloc(buf, buf_size); // recv r = recvfrom(remote_ctx->fd, buf->data, buf_size, 0, (struct sockaddr *)&src_addr, &src_addr_len); if (r == -1) { // error on recv // simply drop that packet ERROR("[udp] remote_recv_recvfrom"); goto CLEAN_UP; } else if (r > packet_size) { if (verbose) { LOGI("[udp] remote_recv_recvfrom fragmentation"); } } buf->len = r; #ifdef MODULE_LOCAL int err = server_ctx->crypto->decrypt_all(buf, server_ctx->crypto->cipher, buf_size); if (err) { // drop the packet silently goto CLEAN_UP; } #ifdef MODULE_REDIR struct sockaddr_storage dst_addr; memset(&dst_addr, 0, sizeof(struct sockaddr_storage)); int len = parse_udprelay_header(buf->data, buf->len, NULL, NULL, &dst_addr); if (dst_addr.ss_family != AF_INET && dst_addr.ss_family != AF_INET6) { LOGI("[udp] ss-redir does not support domain name"); goto CLEAN_UP; } #else int len = parse_udprelay_header(buf->data, buf->len, NULL, NULL, NULL); #endif if (len == 0) { LOGI("[udp] error in parse header"); // error in parse header goto CLEAN_UP; } // server may return using a different address type other than the type we // have used during sending #if defined(MODULE_TUNNEL) || defined(MODULE_REDIR) // Construct packet buf->len -= len; memmove(buf->data, buf->data + len, buf->len); #else #ifdef __ANDROID__ rx += buf->len; stat_update_cb(); #endif // Construct packet brealloc(buf, buf->len + 3, buf_size); memmove(buf->data + 3, buf->data, buf->len); memset(buf->data, 0, 3); buf->len += 3; #endif #endif #ifdef MODULE_REMOTE rx += buf->len; char addr_header_buf[512]; char *addr_header = remote_ctx->addr_header; int addr_header_len = remote_ctx->addr_header_len; if (remote_ctx->af == AF_INET || remote_ctx->af == AF_INET6) { addr_header_len = construct_udprelay_header(&src_addr, addr_header_buf); addr_header = addr_header_buf; } // Construct packet brealloc(buf, buf->len + addr_header_len, buf_size); memmove(buf->data + addr_header_len, buf->data, buf->len); memcpy(buf->data, addr_header, addr_header_len); buf->len += addr_header_len; int err = server_ctx->crypto->encrypt_all(buf, server_ctx->crypto->cipher, buf_size); if (err) { // drop the packet silently goto CLEAN_UP; } #endif if (buf->len > packet_size) { if (verbose) { LOGI("[udp] remote_recv_sendto fragmentation"); } } size_t remote_src_addr_len = get_sockaddr_len((struct sockaddr *)&remote_ctx->src_addr); #ifdef MODULE_REDIR size_t remote_dst_addr_len = get_sockaddr_len((struct sockaddr *)&dst_addr); int src_fd = socket(remote_ctx->src_addr.ss_family, SOCK_DGRAM, 0); if (src_fd < 0) { ERROR("[udp] remote_recv_socket"); goto CLEAN_UP; } int opt = 1; if (setsockopt(src_fd, SOL_IP, IP_TRANSPARENT, &opt, sizeof(opt))) { ERROR("[udp] remote_recv_setsockopt"); close(src_fd); goto CLEAN_UP; } if (setsockopt(src_fd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt))) { ERROR("[udp] remote_recv_setsockopt"); close(src_fd); goto CLEAN_UP; } #ifdef IP_TOS // Set QoS flag int tos = 46; setsockopt(src_fd, IPPROTO_IP, IP_TOS, &tos, sizeof(tos)); #endif if (bind(src_fd, (struct sockaddr *)&dst_addr, remote_dst_addr_len) != 0) { ERROR("[udp] remote_recv_bind"); close(src_fd); goto CLEAN_UP; } int s = sendto(src_fd, buf->data, buf->len, 0, (struct sockaddr *)&remote_ctx->src_addr, remote_src_addr_len); if (s == -1) { ERROR("[udp] remote_recv_sendto"); close(src_fd); goto CLEAN_UP; } close(src_fd); #else int s = sendto(server_ctx->fd, buf->data, buf->len, 0, (struct sockaddr *)&remote_ctx->src_addr, remote_src_addr_len); if (s == -1) { ERROR("[udp] remote_recv_sendto"); goto CLEAN_UP; } #endif // handle the UDP packet successfully, // triger the timer ev_timer_again(EV_A_ & remote_ctx->watcher); CLEAN_UP: bfree(buf); ss_free(buf); }
// Return the disk block address of the nth block in inode ip. // If there is no such block, alloc controls whether one is allocated. uint bmap(struct inode *ip, uint bn, int alloc) { uint addr, *a; struct buf *bp; if(bn < NDIRECT){ if((addr = ip->addrs[bn]) == 0){ if(!alloc) return -1; ip->addrs[bn] = addr = balloc(ip->dev); } return addr; } bn -= NDIRECT; //check indirect if(bn < NINDIRECT){ // Load indirect block, allocating if necessary. if((addr = ip->addrs[INDIRECT]) == 0){ if(!alloc) return -1; //cprintf("allocating indirect block %d in indirect\n", bn); ip->addrs[INDIRECT] = addr = balloc(ip->dev); } bp = bread(ip->dev, addr); a = (uint*)bp->data; if((addr = a[bn]) == 0){ if(!alloc){ brelse(bp); return -1; } //cprintf("allocating data block %d in indirect\n", bn); a[bn] = addr = balloc(ip->dev); bwrite(bp); } brelse(bp); return addr; } //NEW CODE //decrement block number for new reference bn -= NINDIRECT; //DOUBLE INDIRECT if(bn < NDINDIRECT){ //cprintf("bn is %d\n", bn); if((addr = ip->addrs[DINDIRECT]) == 0){ if(!alloc) return -1; ip->addrs[DINDIRECT] = addr = balloc(ip->dev); } bp = bread(ip->dev, addr); a = (uint*)bp->data; //calculate base and offset indirect block in double indirect block uint base = bn / NINDIRECT; uint offset = bn % NINDIRECT; //grab indirect block and allocate if necessary if((addr = a[base]) == 0){ if(!alloc){ brelse(bp); return -1; } //cprintf("allocating new indirect block for bn = %d\n", bn); a[base] = addr = balloc(ip->dev); bwrite(bp); } brelse(bp); bp = bread(ip->dev, addr); a = (uint*)bp->data; //get data block from indirect block if((addr = a[offset]) == 0){ if(!alloc){ brelse(bp); return -1; } //cprintf("allocating new data block with bn = %d\n", bn); a[offset] = addr = balloc(ip->dev); bwrite(bp); } brelse(bp); return addr; } panic("bmap: out of range"); }
int main(int argc, char *argv[]) { int i, cc, fd; uint rootino, inum, off; struct dirent de; char buf[512]; struct dinode din; if(argc < 2){ fprintf(stderr, "Usage: mkfs fs.img files...\n"); exit(1); } assert((512 % sizeof(struct dinode)) == 0); assert((512 % sizeof(struct dirent)) == 0); fsfd = open(argv[1], O_RDWR|O_CREAT|O_TRUNC, 0666); if(fsfd < 0){ perror(argv[1]); exit(1); } sb.size = xint(size); sb.nblocks = xint(nblocks); // so whole disk is size sectors sb.ninodes = xint(ninodes); bitblocks = size/(512*8) + 1; usedblocks = ninodes / IPB + 3 + bitblocks; freeblock = usedblocks; printf("used %d (bit %d ninode %zu) free %u total %d\n", usedblocks, bitblocks, ninodes/IPB + 1, freeblock, nblocks+usedblocks); assert(nblocks + usedblocks == size); for(i = 0; i < nblocks + usedblocks; i++) wsect(i, zeroes); wsect(1, &sb); rootino = ialloc(T_DIR); assert(rootino == ROOTINO); bzero(&de, sizeof(de)); de.inum = xshort(rootino); strcpy(de.name, "."); iappend(rootino, &de, sizeof(de)); bzero(&de, sizeof(de)); de.inum = xshort(rootino); strcpy(de.name, ".."); iappend(rootino, &de, sizeof(de)); for(i = 2; i < argc; i++){ assert(index(argv[i], '/') == 0); if((fd = open(argv[i], 0)) < 0){ perror(argv[i]); exit(1); } // Skip leading _ in name when writing to file system. // The binaries are named _rm, _cat, etc. to keep the // build operating system from trying to execute them // in place of system binaries like rm and cat. if(argv[i][0] == '_') ++argv[i]; inum = ialloc(T_FILE); bzero(&de, sizeof(de)); de.inum = xshort(inum); strncpy(de.name, argv[i], DIRSIZ); iappend(rootino, &de, sizeof(de)); while((cc = read(fd, buf, sizeof(buf))) > 0) iappend(inum, buf, cc); close(fd); } // fix size of root inode dir rinode(rootino, &din); off = xint(din.size); off = ((off/BSIZE) + 1) * BSIZE; din.size = xint(off); winode(rootino, &din); balloc(usedblocks); exit(0); }
int menuhit(int but, Mouse *m, Menu *menu) { int i, nitem, nitemdrawn, maxwid, lasti, off, noff, wid, screenitem; bool scrolling; Rectangle r, menur, sc, textr, scrollr; Bitmap *b; Point pt; char *item; extern unsigned int cursor; unsigned int oldcursor = cursor; cursorswitch(ArrowCursor); sc = screen.clipr; clipr(&screen, screen.r); maxwid = 0; for(nitem = 0; (item = menu->item? menu->item[nitem] : (*menu->gen)(nitem)); nitem++){ i = strwidth(font, item); if(i > maxwid) maxwid = i; } if(menu->lasthit<0 || menu->lasthit>=nitem) menu->lasthit = 0; screenitem = (Dy(screen.r)-10)/(fontheight()+Vspacing); if(nitem>Maxunscroll || nitem>screenitem){ scrolling = true; nitemdrawn = Nscroll; if(nitemdrawn > screenitem) nitemdrawn = screenitem; wid = maxwid + Gap + Scrollwid; off = menu->lasthit - nitemdrawn/2; if(off < 0) off = 0; if(off > nitem-nitemdrawn) off = nitem-nitemdrawn; lasti = menu->lasthit-off; }else{ scrolling = false; nitemdrawn = nitem; wid = maxwid; off = 0; lasti = menu->lasthit; } r = inset(Rect(0, 0, wid, nitemdrawn*(fontheight()+Vspacing)), -Margin); r = rsubp(r, Pt(wid/2, lasti*(fontheight()+Vspacing)+fontheight()/2)); r = raddp(r, m->xy); pt = Pt(0, 0); if(r.max.x>screen.r.max.x) pt.x = screen.r.max.x-r.max.x; if(r.max.y>screen.r.max.y) pt.y = screen.r.max.y-r.max.y; if(r.min.x<screen.r.min.x) pt.x = screen.r.min.x-r.min.x; if(r.min.y<screen.r.min.y) pt.y = screen.r.min.y-r.min.y; menur = raddp(r, pt); textr.max.x = menur.max.x-Margin; textr.min.x = textr.max.x-maxwid; textr.min.y = menur.min.y+Margin; textr.max.y = textr.min.y + nitemdrawn*(fontheight()+Vspacing); if(scrolling){ scrollr = inset(menur, Border); scrollr.max.x = scrollr.min.x+Scrollwid; }else scrollr = Rect(0, 0, 0, 0); b = balloc(menur, screen.ldepth); if(b == 0) b = &screen; bitblt(b, menur.min, &screen, menur, S); bitblt(&screen, menur.min, &screen, menur, 0); border(&screen, menur, Blackborder, F, _bgpixel); r = menurect(textr, lasti); cursorset(divpt(add(r.min, r.max), 2)); menupaint(menu, textr, off, nitemdrawn); if(scrolling) menuscrollpaint(scrollr, off, nitem, nitemdrawn); r = menurect(textr, lasti); cursorset(divpt(add(r.min, r.max), 2)); menupaint(menu, textr, off, nitemdrawn); if(scrolling) menuscrollpaint(scrollr, off, nitem, nitemdrawn); while(m->buttons & (1<<(but-1))){ lasti = menuscan(but, m, textr, lasti); if(lasti >= 0) break; while(!ptinrect(m->xy, textr) && (m->buttons & (1<<(but-1)))){ if(scrolling && ptinrect(m->xy, scrollr)){ noff = ((m->xy.y-scrollr.min.y)*nitem)/Dy(scrollr); noff -= nitemdrawn/2; if(noff < 0) noff = 0; if(noff > nitem-nitemdrawn) noff = nitem-nitemdrawn; if(noff != off){ off = noff; menupaint(menu, textr, off, nitemdrawn); menuscrollpaint(scrollr, off, nitem, nitemdrawn); } } *m = emouse(); } } bitblt(&screen, menur.min, b, menur, S); if(b != &screen) bfree(b); clipr(&screen, sc); if(lasti >= 0){ menu->lasthit = lasti+off; return cursorswitch(oldcursor), menu->lasthit; } cursorswitch(oldcursor); return -1; }
static void remote_send_cb(EV_P_ ev_io *w, int revents) { remote_ctx_t *remote_send_ctx = (remote_ctx_t *)w; remote_t *remote = remote_send_ctx->remote; server_t *server = remote->server; if (!remote_send_ctx->connected) { struct sockaddr_storage addr; socklen_t len = sizeof addr; int r = getpeername(remote->fd, (struct sockaddr *)&addr, &len); if (r == 0) { remote_send_ctx->connected = 1; ev_io_stop(EV_A_ & remote_send_ctx->io); ev_io_stop(EV_A_ & server->recv_ctx->io); ev_timer_stop(EV_A_ & remote_send_ctx->watcher); ev_timer_start(EV_A_ & remote->recv_ctx->watcher); // send destaddr buffer_t ss_addr_to_send; buffer_t *abuf = &ss_addr_to_send; balloc(abuf, BUF_SIZE); if (server->hostname_len > 0) { // HTTP/SNI uint16_t port; if (AF_INET6 == server->destaddr.ss_family) { // IPv6 port = (((struct sockaddr_in6 *)&(server->destaddr))->sin6_port); } else { // IPv4 port = (((struct sockaddr_in *)&(server->destaddr))->sin_port); } abuf->array[abuf->len++] = 3; // Type 3 is hostname abuf->array[abuf->len++] = server->hostname_len; memcpy(abuf->array + abuf->len, server->hostname, server->hostname_len); abuf->len += server->hostname_len; memcpy(abuf->array + abuf->len, &port, 2); } else if (AF_INET6 == server->destaddr.ss_family) { // IPv6 abuf->array[abuf->len++] = 4; // Type 4 is IPv6 address size_t in6_addr_len = sizeof(struct in6_addr); memcpy(abuf->array + abuf->len, &(((struct sockaddr_in6 *)&(server->destaddr))->sin6_addr), in6_addr_len); abuf->len += in6_addr_len; memcpy(abuf->array + abuf->len, &(((struct sockaddr_in6 *)&(server->destaddr))->sin6_port), 2); } else { // IPv4 abuf->array[abuf->len++] = 1; // Type 1 is IPv4 address size_t in_addr_len = sizeof(struct in_addr); memcpy(abuf->array + abuf->len, &((struct sockaddr_in *)&(server->destaddr))->sin_addr, in_addr_len); abuf->len += in_addr_len; memcpy(abuf->array + abuf->len, &((struct sockaddr_in *)&(server->destaddr))->sin_port, 2); } abuf->len += 2; if (auth) { abuf->array[0] |= ONETIMEAUTH_FLAG; ss_onetimeauth(abuf, server->e_ctx->evp.iv, BUF_SIZE); } brealloc(remote->buf, remote->buf->len + abuf->len, BUF_SIZE); memmove(remote->buf->array + abuf->len, remote->buf->array, remote->buf->len); memcpy(remote->buf->array, abuf->array, abuf->len); remote->buf->len += abuf->len; bfree(abuf); int err = ss_encrypt(remote->buf, server->e_ctx, BUF_SIZE); if (err) { LOGE("invalid password or cipher"); close_and_free_remote(EV_A_ remote); close_and_free_server(EV_A_ server); return; } ev_io_start(EV_A_ & remote->recv_ctx->io); } else { ERROR("getpeername"); // not connected close_and_free_remote(EV_A_ remote); close_and_free_server(EV_A_ server); return; } } if (remote->buf->len == 0) { // close and free close_and_free_remote(EV_A_ remote); close_and_free_server(EV_A_ server); return; } else { // has data to send ssize_t s = send(remote->fd, remote->buf->array + remote->buf->idx, remote->buf->len, 0); if (s == -1) { if (errno != EAGAIN && errno != EWOULDBLOCK) { ERROR("send"); // close and free close_and_free_remote(EV_A_ remote); close_and_free_server(EV_A_ server); } return; } else if (s < remote->buf->len) { // partly sent, move memory, wait for the next time to send remote->buf->len -= s; remote->buf->idx += s; return; } else { // all sent out, wait for reading remote->buf->len = 0; remote->buf->idx = 0; ev_io_stop(EV_A_ & remote_send_ctx->io); ev_io_start(EV_A_ & server->recv_ctx->io); } } }
static void * usb_alloc(int size) { void *tmp = balloc(size, NULL); track_address(tmp); return tmp; }