struct link *link_accept(struct link *master, time_t stoptime) { struct link *link = 0; link = link_create(); if(!link) goto failure; while(1) { if(!link_sleep(master, stoptime, 1, 0)) goto failure; link->fd = accept(master->fd, 0, 0); break; } if(!link_nonblocking(link, 1)) goto failure; if(!link_address_remote(link, link->raddr, &link->rport)) goto failure; link_squelch(); debug(D_TCP, "got connection from %s:%d", link->raddr, link->rport); return link; failure: if(link) link_close(link); return 0; }
struct link *link_serve_address(const char *addr, int port) { struct link *link = 0; struct sockaddr_in address; int success; int value; link = link_create(); if(!link) goto failure; link->fd = socket(AF_INET, SOCK_STREAM, 0); if(link->fd < 0) goto failure; value = 1; setsockopt(link->fd, SOL_SOCKET, SO_REUSEADDR, (void *) &value, sizeof(value)); link_window_configure(link); if(addr != 0 || port != LINK_PORT_ANY) { memset(&address, 0, sizeof(address)); #if defined(CCTOOLS_OPSYS_DARWIN) address.sin_len = sizeof(address); #endif address.sin_family = AF_INET; address.sin_port = htons(port); if(addr) { string_to_ip_address(addr, (unsigned char *) &address.sin_addr.s_addr); } else { address.sin_addr.s_addr = htonl(INADDR_ANY); } success = bind(link->fd, (struct sockaddr *) &address, sizeof(address)); if(success < 0) goto failure; } success = listen(link->fd, 5); if(success < 0) goto failure; if(!link_nonblocking(link, 1)) goto failure; debug(D_TCP, "listening on port %d", port); return link; failure: if(link) link_close(link); return 0; }
struct link *link_connect(const char *addr, int port, time_t stoptime) { struct sockaddr_in address; struct link *link = 0; int result; int save_errno; link = link_create(); if(!link) goto failure; link_squelch(); memset(&address, 0, sizeof(address)); #if defined(CCTOOLS_OPSYS_DARWIN) address.sin_len = sizeof(address); #endif address.sin_family = AF_INET; address.sin_port = htons(port); if(!string_to_ip_address(addr, (unsigned char *) &address.sin_addr)) goto failure; link->fd = socket(AF_INET, SOCK_STREAM, 0); if(link->fd < 0) goto failure; link_window_configure(link); /* sadly, cygwin does not do non-blocking connect correctly */ #ifdef CCTOOLS_OPSYS_CYGWIN if(!link_nonblocking(link, 0)) goto failure; #else if(!link_nonblocking(link, 1)) goto failure; #endif debug(D_TCP, "connecting to %s:%d", addr, port); do { result = connect(link->fd, (struct sockaddr *) &address, sizeof(address)); /* On some platforms, errno is not set correctly. */ /* If the remote address can be found, then we are really connected. */ /* Also, on bsd-derived systems, failure to connect is indicated by a second connect returning EINVAL. */ if(result < 0 && !errno_is_temporary(errno)) { if(errno == EINVAL) errno = ECONNREFUSED; break; } if(link_address_remote(link, link->raddr, &link->rport)) { debug(D_TCP, "made connection to %s:%d", link->raddr, link->rport); #ifdef CCTOOLS_OPSYS_CYGWIN link_nonblocking(link, 1); #endif return link; } } while(link_sleep(link, stoptime, 0, 1)); debug(D_TCP, "connection to %s:%d failed (%s)", addr, port, strerror(errno)); failure: save_errno = errno; if(link) link_close(link); errno = save_errno; return 0; }
struct link *link_connect(const char *addr, int port, time_t stoptime) { struct sockaddr_in address; struct link *link = 0; int result; int save_errno; link = link_create(); if(!link) goto failure; link_squelch(); memset(&address, 0, sizeof(address)); #if defined(CCTOOLS_OPSYS_DARWIN) address.sin_len = sizeof(address); #endif address.sin_family = AF_INET; address.sin_port = htons(port); if(!string_to_ip_address(addr, (unsigned char *) &address.sin_addr)) goto failure; link->fd = socket(AF_INET, SOCK_STREAM, 0); if(link->fd < 0) goto failure; link_window_configure(link); /* sadly, cygwin does not do non-blocking connect correctly */ #ifdef CCTOOLS_OPSYS_CYGWIN if(!link_nonblocking(link, 0)) goto failure; #else if(!link_nonblocking(link, 1)) goto failure; #endif debug(D_TCP, "connecting to %s:%d", addr, port); while(1) { // First attempt a non-blocking connect result = connect(link->fd, (struct sockaddr *) &address, sizeof(address)); // On many platforms, non-blocking connect sets errno in unexpected ways: // On OSX, result=-1 and errno==EISCONN indicates a successful connection. if(result<0 && errno==EISCONN) result=0; // On BSD-derived systems, failure to connect is indicated by errno = EINVAL. // Set it to something more explanatory. if(result<0 && errno==EINVAL) errno=ECONNREFUSED; // Otherwise, a non-temporary errno should cause us to bail out. if(result<0 && !errno_is_temporary(errno)) break; // If the remote address is valid, we are connected no matter what. if(link_address_remote(link, link->raddr, &link->rport)) { debug(D_TCP, "made connection to %s:%d", link->raddr, link->rport); #ifdef CCTOOLS_OPSYS_CYGWIN link_nonblocking(link, 1); #endif return link; } // if the time has expired, bail out if( time(0) >= stoptime ) { errno = ETIMEDOUT; break; } // wait for some activity on the socket. link_sleep(link, stoptime, 0, 1); // No matter how the sleep ends, we want to go back to the top // and call connect again to get a proper errno. } debug(D_TCP, "connection to %s:%d failed (%s)", addr, port, strerror(errno)); failure: save_errno = errno; if(link) link_close(link); errno = save_errno; return 0; }
struct link *link_serve_address(const char *addr, int port) { struct link *link = 0; struct sockaddr_in address; int success; int value; link = link_create(); if(!link) goto failure; link->fd = socket(AF_INET, SOCK_STREAM, 0); if(link->fd < 0) goto failure; value = fcntl(link->fd, F_GETFD); if (value == -1) goto failure; value |= FD_CLOEXEC; if (fcntl(link->fd, F_SETFD, value) == -1) goto failure; value = 1; setsockopt(link->fd, SOL_SOCKET, SO_REUSEADDR, (void *) &value, sizeof(value)); link_window_configure(link); memset(&address, 0, sizeof(address)); #if defined(CCTOOLS_OPSYS_DARWIN) address.sin_len = sizeof(address); #endif address.sin_family = AF_INET; if(addr) { string_to_ip_address(addr, (unsigned char *) &address.sin_addr.s_addr); } else { address.sin_addr.s_addr = htonl(INADDR_ANY); } int low = TCP_LOW_PORT_DEFAULT; int high = TCP_HIGH_PORT_DEFAULT; if(port < 1) { const char *lowstr = getenv("TCP_LOW_PORT"); if (lowstr) low = atoi(lowstr); const char *highstr = getenv("TCP_HIGH_PORT"); if (highstr) high = atoi(highstr); } else { low = high = port; } if(high < low) fatal("high port %d is less than low port %d in range", high, low); for (port = low; port <= high; port++) { address.sin_port = htons(port); success = bind(link->fd, (struct sockaddr *) &address, sizeof(address)); if(success == -1) { if(errno == EADDRINUSE) { //If a port is specified, fail! if (low == high) { goto failure; } else { continue; } } else { goto failure; } } break; } success = listen(link->fd, 5); if(success < 0) goto failure; if(!link_nonblocking(link, 1)) goto failure; debug(D_TCP, "listening on port %d", port); return link; failure: if(link) link_close(link); return 0; }
static void handle_query(struct link *query_link) { FILE *stream; char line[LINE_MAX]; char url[LINE_MAX]; char path[LINE_MAX]; char action[LINE_MAX]; char version[LINE_MAX]; char hostport[LINE_MAX]; char addr[LINK_ADDRESS_MAX]; char key[LINE_MAX]; int port; time_t current; char *hkey; struct nvpair *nv; int i, n; link_address_remote(query_link, addr, &port); debug(D_DEBUG, "www query from %s:%d", addr, port); if(link_readline(query_link, line, LINE_MAX, time(0) + HANDLE_QUERY_TIMEOUT)) { string_chomp(line); if(sscanf(line, "%s %s %s", action, url, version) != 3) { return; } // Consume the rest of the query while(1) { if(!link_readline(query_link, line, LINE_MAX, time(0) + HANDLE_QUERY_TIMEOUT)) { return; } if(line[0] == 0) { break; } } } else { return; } // Output response stream = fdopen(link_fd(query_link), "w"); if(!stream) { return; } link_nonblocking(query_link, 0); current = time(0); fprintf(stream, "HTTP/1.1 200 OK\n"); fprintf(stream, "Date: %s", ctime(¤t)); fprintf(stream, "Server: catalog_server\n"); fprintf(stream, "Connection: close\n"); if(sscanf(url, "http://%[^/]%s", hostport, path) == 2) { // continue on } else { strcpy(path, url); } /* load the hash table entries into one big array */ n = 0; nvpair_database_firstkey(table); while(nvpair_database_nextkey(table, &hkey, &nv)) { array[n] = nv; n++; } /* sort the array by name before displaying */ qsort(array, n, sizeof(struct nvpair *), compare_nvpair); if(!strcmp(path, "/query.text")) { fprintf(stream, "Content-type: text/plain\n\n"); for(i = 0; i < n; i++) nvpair_print_text(array[i], stream); } else if(!strcmp(path, "/query.json")) { fprintf(stream, "Content-type: text/plain\n\n"); fprintf(stream,"[\n"); for(i = 0; i < n; i++) { nvpair_print_json(array[i], stream); fprintf(stream,",\n"); } fprintf(stream,"]\n"); } else if(!strcmp(path, "/query.oldclassads")) { fprintf(stream, "Content-type: text/plain\n\n"); for(i = 0; i < n; i++) nvpair_print_old_classads(array[i], stream); } else if(!strcmp(path, "/query.newclassads")) { fprintf(stream, "Content-type: text/plain\n\n"); for(i = 0; i < n; i++) nvpair_print_new_classads(array[i], stream); } else if(!strcmp(path, "/query.xml")) { fprintf(stream, "Content-type: text/xml\n\n"); fprintf(stream, "<?xml version=\"1.0\" standalone=\"yes\"?>\n"); fprintf(stream, "<catalog>\n"); for(i = 0; i < n; i++) nvpair_print_xml(array[i], stream); fprintf(stream, "</catalog>\n"); } else if(sscanf(path, "/detail/%s", key) == 1) { struct nvpair *nv; fprintf(stream, "Content-type: text/html\n\n"); nv = nvpair_database_lookup(table, key); if(nv) { const char *name = nvpair_lookup_string(nv, "name"); if(!name) name = "unknown"; fprintf(stream, "<title>%s catalog server: %s</title>\n", preferred_hostname, name); fprintf(stream, "<center>\n"); fprintf(stream, "<h1>%s catalog server</h1>\n", preferred_hostname); fprintf(stream, "<h2>%s</h2>\n", name); fprintf(stream, "<p><a href=/>return to catalog view</a><p>\n"); nvpair_print_html_solo(nv, stream); fprintf(stream, "</center>\n"); } else { fprintf(stream, "<title>%s catalog server</title>\n", preferred_hostname); fprintf(stream, "<center>\n"); fprintf(stream, "<h1>%s catalog server</h1>\n", preferred_hostname); fprintf(stream, "<h2>Unknown Item!</h2>\n"); fprintf(stream, "</center>\n"); } } else { char avail_line[LINE_MAX]; char total_line[LINE_MAX]; INT64_T sum_total = 0; INT64_T sum_avail = 0; INT64_T sum_devices = 0; fprintf(stream, "Content-type: text/html\n\n"); fprintf(stream, "<title>%s catalog server</title>\n", preferred_hostname); fprintf(stream, "<center>\n"); fprintf(stream, "<h1>%s catalog server</h1>\n", preferred_hostname); fprintf(stream, "<a href=/query.text>text</a> - "); fprintf(stream, "<a href=/query.html>html</a> - "); fprintf(stream, "<a href=/query.xml>xml</a> - "); fprintf(stream, "<a href=/query.json>json</a> - "); fprintf(stream, "<a href=/query.oldclassads>oldclassads</a> - "); fprintf(stream, "<a href=/query.newclassads>newclassads</a>"); fprintf(stream, "<p>\n"); for(i = 0; i < n; i++) { nv = array[i]; sum_total += nvpair_lookup_integer(nv, "total"); sum_avail += nvpair_lookup_integer(nv, "avail"); sum_devices++; } string_metric(sum_avail, -1, avail_line); string_metric(sum_total, -1, total_line); fprintf(stream, "<b>%sB available out of %sB on %d devices</b><p>\n", avail_line, total_line, (int) sum_devices); nvpair_print_html_header(stream, html_headers); for(i = 0; i < n; i++) { nv = array[i]; make_hash_key(nv, key); sprintf(url, "/detail/%s", key); nvpair_print_html_with_link(nv, stream, html_headers, "name", url); } nvpair_print_html_footer(stream, html_headers); fprintf(stream, "</center>\n"); } fclose(stream); }