static void send_response(wurfld_connection_context *ctx) { char *useragent = ctx->useragent; DEBUG1("Worker %p is looking up useragent : %s", pthread_self(), useragent); // this might be unnecessary if libwurfl is thread-safe // XXX - needs to be checked wurfld_get_capabilities(useragent, ctx->output); if (use_http) { char response_header[1024]; sprintf(response_header, "%s 200 OK\r\n" "Content-Type: application/json\r\n" "Content-length: %d\r\n" "Server: wurfld\r\n" "Connection: Close\r\n\r\n", ctx->is_http10 ? "HTTP/1.0" : "HTTP/1.1", fbuf_used(ctx->output)); int err = write_socket(ctx->fd, response_header, strlen(response_header)); if (err != 0) { ERROR("(%p) Can't write the response header : %s", pthread_self(), strerror(errno)); } } if (write_socket(ctx->fd, fbuf_data(ctx->output), fbuf_used(ctx->output)) != 0) { ERROR("(%p) Can't write the response data : %s", pthread_self(), strerror(errno)); } }
size_t shardcache_client_offset(shardcache_client_t *c, void *key, size_t klen, uint32_t offset, void *data, uint32_t dlen) { int fd = -1; char *addr = select_node(c, key, klen, &fd); if (fd < 0) { c->errno = SHARDCACHE_CLIENT_ERROR_NETWORK; snprintf(c->errstr, sizeof(c->errstr), "Can't connect to '%s'", addr); return 0; } fbuf_t value = FBUF_STATIC_INITIALIZER; int rc = offset_from_peer(addr, (char *)c->auth, SHC_HDR_SIGNATURE_SIP, key, klen, offset, dlen, &value, fd); if (rc == 0) { uint32_t to_copy = dlen > fbuf_used(&value) ? fbuf_used(&value) : dlen; if (data) memcpy(data, fbuf_data(&value), to_copy); c->errno = SHARDCACHE_CLIENT_OK; c->errstr[0] = 0; connections_pool_add(c->connections, addr, fd); fbuf_destroy(&value); return to_copy; } else { close(fd); c->errno = SHARDCACHE_CLIENT_ERROR_NODE; snprintf(c->errstr, sizeof(c->errstr), "Can't fetch data from node '%s'", addr); } fbuf_destroy(&value); return 0; }
size_t shardcache_client_get(shardcache_client_t *c, void *key, size_t klen, void **data) { int fd = -1; char *addr = select_node(c, key, klen, &fd); if (fd < 0) { c->errno = SHARDCACHE_CLIENT_ERROR_NETWORK; snprintf(c->errstr, sizeof(c->errstr), "Can't connect to '%s'", addr); return 0; } fbuf_t value = FBUF_STATIC_INITIALIZER; int rc = fetch_from_peer(addr, (char *)c->auth, SHC_HDR_SIGNATURE_SIP, key, klen, &value, fd); if (rc == 0) { size_t size = fbuf_used(&value); if (data) *data = fbuf_data(&value); else fbuf_destroy(&value); c->errno = SHARDCACHE_CLIENT_OK; c->errstr[0] = 0; connections_pool_add(c->connections, addr, fd); return size; } else { close(fd); c->errno = SHARDCACHE_CLIENT_ERROR_NODE; snprintf(c->errstr, sizeof(c->errstr), "Can't fetch data from node '%s'", addr); return 0; } return 0; }
int shardcache_client_migration_begin(shardcache_client_t *c, shardcache_node_t **nodes, int num_nodes) { fbuf_t mgb_message = FBUF_STATIC_INITIALIZER; int i; for (i = 0; i < num_nodes; i++) { if (i > 0) fbuf_add(&mgb_message, ","); fbuf_printf(&mgb_message, "%s:%s", shardcache_node_get_string(nodes[i])); } for (i = 0; i < c->num_shards; i++) { char *addr = shardcache_node_get_address(c->shards[i]); int fd = connections_pool_get(c->connections, addr); if (fd < 0) { c->errno = SHARDCACHE_CLIENT_ERROR_NETWORK; snprintf(c->errstr, sizeof(c->errstr), "Can't connect to '%s'", addr); fbuf_destroy(&mgb_message); return -1; } int rc = migrate_peer(addr, (char *)c->auth, SHC_HDR_SIGNATURE_SIP, fbuf_data(&mgb_message), fbuf_used(&mgb_message), fd); if (rc != 0) { close(fd); c->errno = SHARDCACHE_CLIENT_ERROR_NODE; snprintf(c->errstr, sizeof(c->errstr), "Node '%s' (%s) didn't aknowledge the migration\n", shardcache_node_get_label(c->shards[i]), addr); fbuf_destroy(&mgb_message); // XXX - should we abort migration on peers that have been notified (if any)? return -1; } connections_pool_add(c->connections, addr, fd); } fbuf_destroy(&mgb_message); c->errno = SHARDCACHE_CLIENT_OK; c->errstr[0] = 0; return 0; }
static char *unescape_uri_request(char *uri) { fbuf_t buf = FBUF_STATIC_INITIALIZER; char *p = uri; while (*p != 0) { char *n = p; while (*n != '%' && *n != 0) n++; fbuf_add_binary(&buf, p, n-p); p = n; if (*n != 0) { // p and n now both point to % p+=3; n++; int c; if (sscanf(n, "%02x", &c) == 1) fbuf_add_binary(&buf, (char *)&c, 1); else WARN("Can't unescape uri byte"); } } char *data = fbuf_data(&buf); return data; }
void *worker(void *priv) { wurfld_connection_context *ctx = (wurfld_connection_context *)priv; DEBUG1("Worker %p started on fd %d", pthread_self(), ctx->fd); // we don't need to receive anything anymore on this fd int err = shutdown(ctx->fd, SHUT_RD); if (err != 0) NOTICE("Can't shutdown the receive part of fd %d : %s", ctx->fd, strerror(errno)); int opts = fcntl(ctx->fd, F_GETFL); if (opts >= 0) { err = fcntl(ctx->fd, F_SETFL, opts & (~O_NONBLOCK)); if (err != 0) NOTICE("Can't set blocking mode on fd %d : %s", ctx->fd, strerror(errno)); } else { ERROR("Can't get flags on fd %d : %s", ctx->fd, strerror(errno)); } char *useragent = NULL; fbuf_trim(ctx->input); // parse the request char *request_data = fbuf_data(ctx->input); struct sockaddr_in peer; socklen_t socklen = sizeof(struct sockaddr); getpeername(ctx->fd, (struct sockaddr *)&peer, &socklen); if (use_http && strncmp(request_data, "GET /lookup/", 12) == 0) { char *reqline_start = fbuf_data(ctx->input) + 12; char *reqline_end = reqline_start; while (*reqline_end != '\r' && *reqline_end != '\n') reqline_end++; reqline_end++; char reqline[reqline_end-reqline_start]; snprintf(reqline, reqline_end-reqline_start, "%s", reqline_start); char *httpv = strstr(reqline, " HTTP/1"); if (httpv) { *httpv = 0; httpv++; ctx->is_http10 = (strncmp(httpv, "HTTP/1.0", 8) == 0); } useragent = unescape_uri_request(reqline); } else if (!use_http) { useragent = strdup(fbuf_data(ctx->input)); } if (useragent) { NOTICE("(%p) Lookup request from %s: %s", pthread_self(), inet_ntoa(peer.sin_addr), useragent); ctx->useragent = useragent; send_response(ctx); } else if (use_http) { NOTICE("(%p) Unsupported Request from %s: %s", pthread_self(), inet_ntoa(peer.sin_addr), request_data); char response[2048]; snprintf(response, sizeof(response), "%s 400 NOT SUPPORTED\r\n" "Content-Type: text/plain\r\n" "Content-Length: 17\r\n\r\n" "400 NOT SUPPORTED", ctx->is_http10 ? "HTTP/1.0" : "HTTP/1.1"); if (write_socket(ctx->fd, response, strlen(response)) != 0) { ERROR("Worker %p failed writing reponse: %s", pthread_self(), strerror(errno)); } } DEBUG1("Worker %p finished on fd %d", pthread_self(), ctx->fd); shutdown(ctx->fd, SHUT_RDWR); close(ctx->fd); fbuf_free(ctx->input); fbuf_free(ctx->output); free(ctx->useragent); free(ctx); return NULL; }
char *expression_dump(expression_t *expr) { fbuf_t buf = FBUF_STATIC_INITIALIZER; expression_dump_internal(expr, &buf); return fbuf_data(&buf); }