static struct altsvc *altsvc_createid(const char *srchost, const char *dsthost, enum alpnid srcalpnid, enum alpnid dstalpnid, unsigned int srcport, unsigned int dstport) { struct altsvc *as = calloc(sizeof(struct altsvc), 1); if(!as) return NULL; as->srchost = strdup(srchost); if(!as->srchost) goto error; as->dsthost = strdup(dsthost); if(!as->dsthost) goto error; as->srcalpnid = srcalpnid; as->dstalpnid = dstalpnid; as->srcport = curlx_ultous(srcport); as->dstport = curlx_ultous(dstport); return as; error: altsvc_free(as); return NULL; }
int main(int argc, char *argv[]) { srvr_sockaddr_union_t me; curl_socket_t sock = CURL_SOCKET_BAD; curl_socket_t msgsock = CURL_SOCKET_BAD; int wrotepidfile = 0; char *pidname= (char *)".sockfilt.pid"; bool juggle_again; int rc; int error; int arg=1; enum sockmode mode = PASSIVE_LISTEN; /* default */ const char *addr = NULL; while(argc>arg) { if(!strcmp("--version", argv[arg])) { printf("sockfilt IPv4%s\n", #ifdef ENABLE_IPV6 "/IPv6" #else "" #endif ); return 0; } else if(!strcmp("--verbose", argv[arg])) { verbose = TRUE; arg++; } else if(!strcmp("--pidfile", argv[arg])) { arg++; if(argc>arg) pidname = argv[arg++]; } else if(!strcmp("--logfile", argv[arg])) { arg++; if(argc>arg) serverlogfile = argv[arg++]; } else if(!strcmp("--ipv6", argv[arg])) { #ifdef ENABLE_IPV6 ipv_inuse = "IPv6"; use_ipv6 = TRUE; #endif arg++; } else if(!strcmp("--ipv4", argv[arg])) { /* for completeness, we support this option as well */ #ifdef ENABLE_IPV6 ipv_inuse = "IPv4"; use_ipv6 = FALSE; #endif arg++; } else if(!strcmp("--bindonly", argv[arg])) { bind_only = TRUE; arg++; } else if(!strcmp("--port", argv[arg])) { arg++; if(argc>arg) { char *endptr; unsigned long ulnum = strtoul(argv[arg], &endptr, 10); if((endptr != argv[arg] + strlen(argv[arg])) || ((ulnum != 0UL) && ((ulnum < 1025UL) || (ulnum > 65535UL)))) { fprintf(stderr, "sockfilt: invalid --port argument (%s)\n", argv[arg]); return 0; } port = curlx_ultous(ulnum); arg++; } } else if(!strcmp("--connect", argv[arg])) { /* Asked to actively connect to the specified local port instead of doing a passive server-style listening. */ arg++; if(argc>arg) { char *endptr; unsigned long ulnum = strtoul(argv[arg], &endptr, 10); if((endptr != argv[arg] + strlen(argv[arg])) || (ulnum < 1025UL) || (ulnum > 65535UL)) { fprintf(stderr, "sockfilt: invalid --connect argument (%s)\n", argv[arg]); return 0; } connectport = curlx_ultous(ulnum); arg++; } } else if(!strcmp("--addr", argv[arg])) { /* Set an IP address to use with --connect; otherwise use localhost */ arg++; if(argc>arg) { addr = argv[arg]; arg++; } } else { puts("Usage: sockfilt [option]\n" " --version\n" " --verbose\n" " --logfile [file]\n" " --pidfile [file]\n" " --ipv4\n" " --ipv6\n" " --bindonly\n" " --port [port]\n" " --connect [port]\n" " --addr [address]"); return 0; } } #ifdef WIN32 win32_init(); atexit(win32_cleanup); setmode(fileno(stdin), O_BINARY); setmode(fileno(stdout), O_BINARY); setmode(fileno(stderr), O_BINARY); #endif install_signal_handlers(); #ifdef ENABLE_IPV6 if(!use_ipv6) #endif sock = socket(AF_INET, SOCK_STREAM, 0); #ifdef ENABLE_IPV6 else sock = socket(AF_INET6, SOCK_STREAM, 0); #endif if(CURL_SOCKET_BAD == sock) { error = SOCKERRNO; logmsg("Error creating socket: (%d) %s", error, strerror(error)); write_stdout("FAIL\n", 5); goto sockfilt_cleanup; } if(connectport) { /* Active mode, we should connect to the given port number */ mode = ACTIVE; #ifdef ENABLE_IPV6 if(!use_ipv6) { #endif memset(&me.sa4, 0, sizeof(me.sa4)); me.sa4.sin_family = AF_INET; me.sa4.sin_port = htons(connectport); me.sa4.sin_addr.s_addr = INADDR_ANY; if (!addr) addr = "127.0.0.1"; Curl_inet_pton(AF_INET, addr, &me.sa4.sin_addr); rc = connect(sock, &me.sa, sizeof(me.sa4)); #ifdef ENABLE_IPV6 } else { memset(&me.sa6, 0, sizeof(me.sa6)); me.sa6.sin6_family = AF_INET6; me.sa6.sin6_port = htons(connectport); if (!addr) addr = "::1"; Curl_inet_pton(AF_INET6, addr, &me.sa6.sin6_addr); rc = connect(sock, &me.sa, sizeof(me.sa6)); } #endif /* ENABLE_IPV6 */ if(rc) { error = SOCKERRNO; logmsg("Error connecting to port %hu: (%d) %s", connectport, error, strerror(error)); write_stdout("FAIL\n", 5); goto sockfilt_cleanup; } logmsg("====> Client connect"); msgsock = sock; /* use this as stream */ } else { /* passive daemon style */ sock = sockdaemon(sock, &port); if(CURL_SOCKET_BAD == sock) { write_stdout("FAIL\n", 5); goto sockfilt_cleanup; } msgsock = CURL_SOCKET_BAD; /* no stream socket yet */ } logmsg("Running %s version", ipv_inuse); if(connectport) logmsg("Connected to port %hu", connectport); else if(bind_only) logmsg("Bound without listening on port %hu", port); else logmsg("Listening on port %hu", port); wrotepidfile = write_pidfile(pidname); if(!wrotepidfile) { write_stdout("FAIL\n", 5); goto sockfilt_cleanup; } do { juggle_again = juggle(&msgsock, sock, &mode); } while(juggle_again); sockfilt_cleanup: if((msgsock != sock) && (msgsock != CURL_SOCKET_BAD)) sclose(msgsock); if(sock != CURL_SOCKET_BAD) sclose(sock); if(wrotepidfile) unlink(pidname); restore_signal_handlers(); if(got_exit_signal) { logmsg("============> sockfilt exits with signal (%d)", exit_signal); /* * To properly set the return status of the process we * must raise the same signal SIGINT or SIGTERM that we * caught and let the old handler take care of it. */ raise(exit_signal); } logmsg("============> sockfilt quits"); return 0; }
int main(int argc, char *argv[]) { srvr_sockaddr_union_t me; curl_socket_t sock = CURL_SOCKET_BAD; curl_socket_t msgsock = CURL_SOCKET_BAD; int wrotepidfile = 0; int flag; unsigned short port = DEFAULT_PORT; char *pidname= (char *)".rtsp.pid"; struct httprequest req; int rc; int error; int arg=1; long pid; while(argc>arg) { if(!strcmp("--version", argv[arg])) { printf("rtspd IPv4%s" "\n" , #ifdef ENABLE_IPV6 "/IPv6" #else "" #endif ); return 0; } else if(!strcmp("--pidfile", argv[arg])) { arg++; if(argc>arg) pidname = argv[arg++]; } else if(!strcmp("--logfile", argv[arg])) { arg++; if(argc>arg) serverlogfile = argv[arg++]; } else if(!strcmp("--ipv4", argv[arg])) { #ifdef ENABLE_IPV6 ipv_inuse = "IPv4"; use_ipv6 = FALSE; #endif arg++; } else if(!strcmp("--ipv6", argv[arg])) { #ifdef ENABLE_IPV6 ipv_inuse = "IPv6"; use_ipv6 = TRUE; #endif arg++; } else if(!strcmp("--port", argv[arg])) { arg++; if(argc>arg) { char *endptr; unsigned long ulnum = strtoul(argv[arg], &endptr, 10); if((endptr != argv[arg] + strlen(argv[arg])) || (ulnum < 1025UL) || (ulnum > 65535UL)) { fprintf(stderr, "rtspd: invalid --port argument (%s)\n", argv[arg]); return 0; } port = curlx_ultous(ulnum); arg++; } } else if(!strcmp("--srcdir", argv[arg])) { arg++; if(argc>arg) { path = argv[arg]; arg++; } } else { puts("Usage: rtspd [option]\n" " --version\n" " --logfile [file]\n" " --pidfile [file]\n" " --ipv4\n" " --ipv6\n" " --port [port]\n" " --srcdir [path]"); return 0; } } #ifdef WIN32 win32_init(); atexit(win32_cleanup); #endif install_signal_handlers(); pid = (long)getpid(); #ifdef ENABLE_IPV6 if(!use_ipv6) #endif sock = socket(AF_INET, SOCK_STREAM, 0); #ifdef ENABLE_IPV6 else sock = socket(AF_INET6, SOCK_STREAM, 0); #endif if(CURL_SOCKET_BAD == sock) { error = SOCKERRNO; logmsg("Error creating socket: (%d) %s", error, strerror(error)); goto server_cleanup; } flag = 1; if (0 != setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (void *)&flag, sizeof(flag))) { error = SOCKERRNO; logmsg("setsockopt(SO_REUSEADDR) failed with error: (%d) %s", error, strerror(error)); goto server_cleanup; } #ifdef ENABLE_IPV6 if(!use_ipv6) { #endif memset(&me.sa4, 0, sizeof(me.sa4)); me.sa4.sin_family = AF_INET; me.sa4.sin_addr.s_addr = INADDR_ANY; me.sa4.sin_port = htons(port); rc = bind(sock, &me.sa, sizeof(me.sa4)); #ifdef ENABLE_IPV6 } else { memset(&me.sa6, 0, sizeof(me.sa6)); me.sa6.sin6_family = AF_INET6; me.sa6.sin6_addr = in6addr_any; me.sa6.sin6_port = htons(port); rc = bind(sock, &me.sa, sizeof(me.sa6)); } #endif /* ENABLE_IPV6 */ if(0 != rc) { error = SOCKERRNO; logmsg("Error binding socket on port %hu: (%d) %s", port, error, strerror(error)); goto server_cleanup; } logmsg("Running %s version on port %d", ipv_inuse, (int)port); /* start accepting connections */ rc = listen(sock, 5); if(0 != rc) { error = SOCKERRNO; logmsg("listen() failed with error: (%d) %s", error, strerror(error)); goto server_cleanup; } /* ** As soon as this server writes its pid file the test harness will ** attempt to connect to this server and initiate its verification. */ wrotepidfile = write_pidfile(pidname); if(!wrotepidfile) goto server_cleanup; for (;;) { msgsock = accept(sock, NULL, NULL); if(got_exit_signal) break; if (CURL_SOCKET_BAD == msgsock) { error = SOCKERRNO; logmsg("MAJOR ERROR: accept() failed with error: (%d) %s", error, strerror(error)); break; } /* ** As soon as this server acepts a connection from the test harness it ** must set the server logs advisor read lock to indicate that server ** logs should not be read until this lock is removed by this server. */ set_advisor_read_lock(SERVERLOGS_LOCK); serverlogslocked = 1; logmsg("====> Client connect"); #ifdef TCP_NODELAY /* * Disable the Nagle algorithm to make it easier to send out a large * response in many small segments to torture the clients more. */ flag = 1; if (setsockopt(msgsock, IPPROTO_TCP, TCP_NODELAY, (void *)&flag, sizeof(flag)) == -1) { logmsg("====> TCP_NODELAY failed"); } #endif /* initialization of httprequest struct is done in get_request(), but due to pipelining treatment the pipelining struct field must be initialized previously to FALSE every time a new connection arrives. */ req.pipelining = FALSE; do { if(got_exit_signal) break; if(get_request(msgsock, &req)) /* non-zero means error, break out of loop */ break; if(prevbounce) { /* bounce treatment requested */ if((req.testno == prevtestno) && (req.partno == prevpartno)) { req.partno++; logmsg("BOUNCE part number to %ld", req.partno); } else { prevbounce = FALSE; prevtestno = -1; prevpartno = -1; } } send_doc(msgsock, &req); if(got_exit_signal) break; if((req.testno < 0) && (req.testno != DOCNUMBER_CONNECT)) { logmsg("special request received, no persistency"); break; } if(!req.open) { logmsg("instructed to close connection after server-reply"); break; } if(req.open) logmsg("=> persistant connection request ended, awaits new request"); /* if we got a CONNECT, loop and get another request as well! */ } while(req.open || (req.testno == DOCNUMBER_CONNECT)); if(got_exit_signal) break; logmsg("====> Client disconnect"); sclose(msgsock); msgsock = CURL_SOCKET_BAD; if(serverlogslocked) { serverlogslocked = 0; clear_advisor_read_lock(SERVERLOGS_LOCK); } if (req.testno == DOCNUMBER_QUIT) break; } server_cleanup: if((msgsock != sock) && (msgsock != CURL_SOCKET_BAD)) sclose(msgsock); if(sock != CURL_SOCKET_BAD) sclose(sock); if(got_exit_signal) logmsg("signalled to die"); if(wrotepidfile) unlink(pidname); if(serverlogslocked) { serverlogslocked = 0; clear_advisor_read_lock(SERVERLOGS_LOCK); } restore_signal_handlers(); if(got_exit_signal) { logmsg("========> %s rtspd (port: %d pid: %ld) exits with signal (%d)", ipv_inuse, (int)port, pid, exit_signal); /* * To properly set the return status of the process we * must raise the same signal SIGINT or SIGTERM that we * caught and let the old handler take care of it. */ raise(exit_signal); } logmsg("========> rtspd quits"); return 0; }
/* * Curl_altsvc_parse() takes an incoming alt-svc response header and stores * the data correctly in the cache. * * 'value' points to the header *value*. That's contents to the right of the * header name. */ CURLcode Curl_altsvc_parse(struct Curl_easy *data, struct altsvcinfo *asi, const char *value, enum alpnid srcalpnid, const char *srchost, unsigned short srcport) { const char *p = value; size_t len; enum alpnid dstalpnid = srcalpnid; /* the same by default */ char namebuf[MAX_ALTSVC_HOSTLEN] = ""; char alpnbuf[MAX_ALTSVC_ALPNLEN] = ""; struct altsvc *as; unsigned short dstport = srcport; /* the same by default */ const char *semip; time_t maxage = 24 * 3600; /* default is 24 hours */ bool persist = FALSE; CURLcode result = getalnum(&p, alpnbuf, sizeof(alpnbuf)); if(result) return result; DEBUGASSERT(asi); /* Flush all cached alternatives for this source origin, if any */ altsvc_flush(asi, srcalpnid, srchost, srcport); /* "clear" is a magic keyword */ if(strcasecompare(alpnbuf, "clear")) { /* TODO: clear whatever it is it should clear */ return CURLE_OK; } /* The 'ma' and 'persist' flags are annoyingly meant for all alternatives but are set after the list on the line. Scan for the semicolons and get those fields first! */ semip = p; do { semip = strchr(semip, ';'); if(semip) { char option[32]; unsigned long num; char *end_ptr; semip++; /* pass the semicolon */ result = getalnum(&semip, option, sizeof(option)); if(result) break; while(*semip && ISBLANK(*semip)) semip++; if(*semip != '=') continue; semip++; num = strtoul(semip, &end_ptr, 10); if(num < ULONG_MAX) { if(strcasecompare("ma", option)) maxage = num; else if(strcasecompare("persist", option) && (num == 1)) persist = TRUE; } semip = end_ptr; } } while(semip); do { if(*p == '=') { /* [protocol]="[host][:port]" */ dstalpnid = alpn2alpnid(alpnbuf); if(!dstalpnid) { infof(data, "Unknown alt-svc protocol \"%s\", ignoring...\n", alpnbuf); return CURLE_OK; } p++; if(*p == '\"') { const char *dsthost; p++; if(*p != ':') { /* host name starts here */ const char *hostp = p; while(*p && (ISALNUM(*p) || (*p == '.') || (*p == '-'))) p++; len = p - hostp; if(!len || (len >= MAX_ALTSVC_HOSTLEN)) return CURLE_BAD_FUNCTION_ARGUMENT; /* TODO: improve error code */ memcpy(namebuf, hostp, len); namebuf[len] = 0; dsthost = namebuf; } else { /* no destination name, use source host */ dsthost = srchost; } if(*p == ':') { /* a port number */ char *end_ptr; unsigned long port = strtoul(++p, &end_ptr, 10); if(port > USHRT_MAX || end_ptr == p || *end_ptr != '\"') { infof(data, "Unknown alt-svc port number, ignoring...\n"); return CURLE_OK; } p = end_ptr; dstport = curlx_ultous(port); } if(*p++ != '\"') return CURLE_BAD_FUNCTION_ARGUMENT; as = altsvc_createid(srchost, dsthost, srcalpnid, dstalpnid, srcport, dstport); if(as) { /* TODO: the expires time also needs to take the Age: value (if any) into account. [See RFC 7838 section 3.1] */ as->expires = maxage + time(NULL); as->persist = persist; Curl_llist_insert_next(&asi->list, asi->list.tail, as, &as->node); asi->num++; /* one more entry */ infof(data, "Added alt-svc: %s:%d over %s\n", dsthost, dstport, Curl_alpnid2str(dstalpnid)); } } /* after the double quote there can be a comma if there's another string or a semicolon if no more */ if(*p == ',') { /* comma means another alternative is presented */ p++; result = getalnum(&p, alpnbuf, sizeof(alpnbuf)); if(result) /* failed to parse, but since we already did at least one host we return OK */ return CURLE_OK; } } } while(*p && (*p != ';') && (*p != '\n') && (*p != '\r')); return CURLE_OK; }
int main(int argc, char **argv) { srvr_sockaddr_union_t me; struct tftphdr *tp; ssize_t n = 0; int arg = 1; unsigned short port = DEFAULT_PORT; curl_socket_t sock = CURL_SOCKET_BAD; int flag; int rc; int error; long pid; struct testcase test; int result = 0; memset(&test, 0, sizeof(test)); while(argc>arg) { if(!strcmp("--version", argv[arg])) { printf("tftpd IPv4%s\n", #ifdef ENABLE_IPV6 "/IPv6" #else "" #endif ); return 0; } else if(!strcmp("--pidfile", argv[arg])) { arg++; if(argc>arg) pidname = argv[arg++]; } else if(!strcmp("--logfile", argv[arg])) { arg++; if(argc>arg) serverlogfile = argv[arg++]; } else if(!strcmp("--ipv4", argv[arg])) { #ifdef ENABLE_IPV6 ipv_inuse = "IPv4"; use_ipv6 = FALSE; #endif arg++; } else if(!strcmp("--ipv6", argv[arg])) { #ifdef ENABLE_IPV6 ipv_inuse = "IPv6"; use_ipv6 = TRUE; #endif arg++; } else if(!strcmp("--port", argv[arg])) { arg++; if(argc>arg) { char *endptr; unsigned long ulnum = strtoul(argv[arg], &endptr, 10); if((endptr != argv[arg] + strlen(argv[arg])) || (ulnum < 1025UL) || (ulnum > 65535UL)) { fprintf(stderr, "tftpd: invalid --port argument (%s)\n", argv[arg]); return 0; } port = curlx_ultous(ulnum); arg++; } } else if(!strcmp("--srcdir", argv[arg])) { arg++; if(argc>arg) { path = argv[arg]; arg++; } } else { puts("Usage: tftpd [option]\n" " --version\n" " --logfile [file]\n" " --pidfile [file]\n" " --ipv4\n" " --ipv6\n" " --port [port]\n" " --srcdir [path]"); return 0; } } #ifdef WIN32 win32_init(); atexit(win32_cleanup); #endif install_signal_handlers(); pid = (long)getpid(); #ifdef ENABLE_IPV6 if(!use_ipv6) #endif sock = socket(AF_INET, SOCK_DGRAM, 0); #ifdef ENABLE_IPV6 else sock = socket(AF_INET6, SOCK_DGRAM, 0); #endif if(CURL_SOCKET_BAD == sock) { error = SOCKERRNO; logmsg("Error creating socket: (%d) %s", error, strerror(error)); result = 1; goto tftpd_cleanup; } flag = 1; if (0 != setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (void *)&flag, sizeof(flag))) { error = SOCKERRNO; logmsg("setsockopt(SO_REUSEADDR) failed with error: (%d) %s", error, strerror(error)); result = 1; goto tftpd_cleanup; } #ifdef ENABLE_IPV6 if(!use_ipv6) { #endif memset(&me.sa4, 0, sizeof(me.sa4)); me.sa4.sin_family = AF_INET; me.sa4.sin_addr.s_addr = INADDR_ANY; me.sa4.sin_port = htons(port); rc = bind(sock, &me.sa, sizeof(me.sa4)); #ifdef ENABLE_IPV6 } else { memset(&me.sa6, 0, sizeof(me.sa6)); me.sa6.sin6_family = AF_INET6; me.sa6.sin6_addr = in6addr_any; me.sa6.sin6_port = htons(port); rc = bind(sock, &me.sa, sizeof(me.sa6)); } #endif /* ENABLE_IPV6 */ if(0 != rc) { error = SOCKERRNO; logmsg("Error binding socket on port %hu: (%d) %s", port, error, strerror(error)); result = 1; goto tftpd_cleanup; } wrotepidfile = write_pidfile(pidname); if(!wrotepidfile) { result = 1; goto tftpd_cleanup; } logmsg("Running %s version on port UDP/%d", ipv_inuse, (int)port); for (;;) { fromlen = sizeof(from); #ifdef ENABLE_IPV6 if(!use_ipv6) #endif fromlen = sizeof(from.sa4); #ifdef ENABLE_IPV6 else fromlen = sizeof(from.sa6); #endif n = (ssize_t)recvfrom(sock, &buf.storage[0], sizeof(buf.storage), 0, &from.sa, &fromlen); if(got_exit_signal) break; if (n < 0) { logmsg("recvfrom"); result = 3; break; } set_advisor_read_lock(SERVERLOGS_LOCK); serverlogslocked = 1; #ifdef ENABLE_IPV6 if(!use_ipv6) { #endif from.sa4.sin_family = AF_INET; peer = socket(AF_INET, SOCK_DGRAM, 0); if(CURL_SOCKET_BAD == peer) { logmsg("socket"); result = 2; break; } if(connect(peer, &from.sa, sizeof(from.sa4)) < 0) { logmsg("connect: fail"); result = 1; break; } #ifdef ENABLE_IPV6 } else { from.sa6.sin6_family = AF_INET6; peer = socket(AF_INET6, SOCK_DGRAM, 0); if(CURL_SOCKET_BAD == peer) { logmsg("socket"); result = 2; break; } if (connect(peer, &from.sa, sizeof(from.sa6)) < 0) { logmsg("connect: fail"); result = 1; break; } } #endif maxtimeout = 5*TIMEOUT; tp = &buf.hdr; tp->th_opcode = ntohs(tp->th_opcode); if (tp->th_opcode == opcode_RRQ || tp->th_opcode == opcode_WRQ) { memset(&test, 0, sizeof(test)); if (do_tftp(&test, tp, n) < 0) break; if(test.buffer) free(test.buffer); } sclose(peer); peer = CURL_SOCKET_BAD; if(test.ofile > 0) { close(test.ofile); test.ofile = 0; } if(got_exit_signal) break; if(serverlogslocked) { serverlogslocked = 0; clear_advisor_read_lock(SERVERLOGS_LOCK); } logmsg("end of one transfer"); } tftpd_cleanup: if(test.ofile > 0) close(test.ofile); if((peer != sock) && (peer != CURL_SOCKET_BAD)) sclose(peer); if(sock != CURL_SOCKET_BAD) sclose(sock); if(got_exit_signal) logmsg("signalled to die"); if(wrotepidfile) unlink(pidname); if(serverlogslocked) { serverlogslocked = 0; clear_advisor_read_lock(SERVERLOGS_LOCK); } restore_signal_handlers(); if(got_exit_signal) { logmsg("========> %s tftpd (port: %d pid: %ld) exits with signal (%d)", ipv_inuse, (int)port, pid, exit_signal); /* * To properly set the return status of the process we * must raise the same signal SIGINT or SIGTERM that we * caught and let the old handler take care of it. */ raise(exit_signal); } logmsg("========> tftpd quits"); return result; }