12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636263726382639264026412642264326442645264626472648264926502651265226532654265526562657265826592660266126622663266426652666266726682669267026712672267326742675267626772678267926802681268226832684268526862687268826892690269126922693269426952696269726982699270027012702270327042705270627072708270927102711271227132714271527162717271827192720272127222723272427252726272727282729273027312732273327342735273627372738273927402741274227432744274527462747274827492750275127522753275427552756275727582759276027612762276327642765276627672768276927702771277227732774277527762777277827792780278127822783278427852786278727882789279027912792279327942795279627972798279928002801280228032804280528062807280828092810281128122813281428152816281728182819282028212822282328242825282628272828282928302831283228332834283528362837283828392840284128422843284428452846284728482849285028512852285328542855285628572858285928602861286228632864286528662867286828692870287128722873287428752876287728782879288028812882288328842885288628872888288928902891289228932894289528962897289828992900290129022903290429052906290729082909291029112912291329142915291629172918291929202921292229232924292529262927292829292930293129322933293429352936293729382939294029412942294329442945294629472948294929502951295229532954295529562957295829592960296129622963296429652966296729682969297029712972297329742975297629772978297929802981298229832984298529862987298829892990299129922993299429952996299729982999300030013002300330043005300630073008300930103011301230133014301530163017301830193020302130223023302430253026302730283029303030313032303330343035303630373038303930403041304230433044304530463047304830493050305130523053305430553056305730583059306030613062306330643065306630673068306930703071307230733074307530763077307830793080308130823083308430853086308730883089309030913092309330943095309630973098309931003101310231033104310531063107310831093110311131123113311431153116311731183119312031213122312331243125312631273128312931303131313231333134313531363137313831393140314131423143314431453146314731483149315031513152315331543155315631573158315931603161316231633164316531663167316831693170317131723173317431753176317731783179318031813182318331843185318631873188318931903191319231933194319531963197319831993200320132023203320432053206320732083209321032113212321332143215321632173218321932203221322232233224322532263227322832293230323132323233323432353236323732383239324032413242324332443245324632473248324932503251325232533254325532563257325832593260326132623263326432653266326732683269327032713272327332743275327632773278327932803281328232833284328532863287328832893290329132923293329432953296329732983299330033013302330333043305330633073308330933103311331233133314331533163317331833193320332133223323332433253326332733283329333033313332333333343335333633373338333933403341334233433344334533463347334833493350335133523353335433553356335733583359336033613362336333643365336633673368336933703371337233733374337533763377337833793380338133823383338433853386338733883389339033913392339333943395339633973398339934003401340234033404340534063407340834093410341134123413341434153416341734183419342034213422342334243425342634273428342934303431343234333434 |
- #include "or.h"
- static connection_t *connection_create_listener(
- struct sockaddr *listensockaddr,
- socklen_t listensocklen, int type,
- char* address);
- static void connection_init(time_t now, connection_t *conn, int type,
- int socket_family);
- static int connection_init_accepted_conn(connection_t *conn,
- uint8_t listener_type);
- static int connection_handle_listener_read(connection_t *conn, int new_type);
- static int connection_read_bucket_should_increase(or_connection_t *conn);
- static int connection_finished_flushing(connection_t *conn);
- static int connection_flushed_some(connection_t *conn);
- static int connection_finished_connecting(connection_t *conn);
- static int connection_reached_eof(connection_t *conn);
- static int connection_read_to_buf(connection_t *conn, int *max_to_read,
- int *socket_error);
- static int connection_process_inbuf(connection_t *conn, int package_partial);
- static void client_check_address_changed(int sock);
- static void set_constrained_socket_buffers(int sock, int size);
- static const char *connection_proxy_state_to_string(int state);
- static int connection_read_https_proxy_response(connection_t *conn);
- static void connection_send_socks5_connect(connection_t *conn);
- static uint32_t last_interface_ip = 0;
- static smartlist_t *outgoing_addrs = NULL;
- const char *
- conn_type_to_string(int type)
- {
- static char buf[64];
- switch (type) {
- case CONN_TYPE_OR_LISTENER: return "OR listener";
- case CONN_TYPE_OR: return "OR";
- case CONN_TYPE_EXIT: return "Exit";
- case CONN_TYPE_AP_LISTENER: return "Socks listener";
- case CONN_TYPE_AP_TRANS_LISTENER:
- return "Transparent pf/netfilter listener";
- case CONN_TYPE_AP_NATD_LISTENER: return "Transparent natd listener";
- case CONN_TYPE_AP_DNS_LISTENER: return "DNS listener";
- case CONN_TYPE_AP: return "Socks";
- case CONN_TYPE_DIR_LISTENER: return "Directory listener";
- case CONN_TYPE_DIR: return "Directory";
- case CONN_TYPE_CPUWORKER: return "CPU worker";
- case CONN_TYPE_CONTROL_LISTENER: return "Control listener";
- case CONN_TYPE_CONTROL: return "Control";
- default:
- log_warn(LD_BUG, "unknown connection type %d", type);
- tor_snprintf(buf, sizeof(buf), "unknown [%d]", type);
- return buf;
- }
- }
- const char *
- conn_state_to_string(int type, int state)
- {
- static char buf[96];
- switch (type) {
- case CONN_TYPE_OR_LISTENER:
- case CONN_TYPE_AP_LISTENER:
- case CONN_TYPE_AP_TRANS_LISTENER:
- case CONN_TYPE_AP_NATD_LISTENER:
- case CONN_TYPE_AP_DNS_LISTENER:
- case CONN_TYPE_DIR_LISTENER:
- case CONN_TYPE_CONTROL_LISTENER:
- if (state == LISTENER_STATE_READY)
- return "ready";
- break;
- case CONN_TYPE_OR:
- switch (state) {
- case OR_CONN_STATE_CONNECTING: return "connect()ing";
- case OR_CONN_STATE_PROXY_HANDSHAKING: return "handshaking (proxy)";
- case OR_CONN_STATE_TLS_HANDSHAKING: return "handshaking (TLS)";
- case OR_CONN_STATE_TLS_CLIENT_RENEGOTIATING:
- return "renegotiating (TLS)";
- case OR_CONN_STATE_TLS_SERVER_RENEGOTIATING:
- return "waiting for renegotiation (TLS)";
- case OR_CONN_STATE_OR_HANDSHAKING: return "handshaking (Tor)";
- case OR_CONN_STATE_OPEN: return "open";
- }
- break;
- case CONN_TYPE_EXIT:
- switch (state) {
- case EXIT_CONN_STATE_RESOLVING: return "waiting for dest info";
- case EXIT_CONN_STATE_CONNECTING: return "connecting";
- case EXIT_CONN_STATE_OPEN: return "open";
- case EXIT_CONN_STATE_RESOLVEFAILED: return "resolve failed";
- }
- break;
- case CONN_TYPE_AP:
- switch (state) {
- case AP_CONN_STATE_SOCKS_WAIT: return "waiting for socks info";
- case AP_CONN_STATE_NATD_WAIT: return "waiting for natd dest info";
- case AP_CONN_STATE_RENDDESC_WAIT: return "waiting for rendezvous desc";
- case AP_CONN_STATE_CONTROLLER_WAIT: return "waiting for controller";
- case AP_CONN_STATE_CIRCUIT_WAIT: return "waiting for circuit";
- case AP_CONN_STATE_CONNECT_WAIT: return "waiting for connect response";
- case AP_CONN_STATE_RESOLVE_WAIT: return "waiting for resolve response";
- case AP_CONN_STATE_OPEN: return "open";
- }
- break;
- case CONN_TYPE_DIR:
- switch (state) {
- case DIR_CONN_STATE_CONNECTING: return "connecting";
- case DIR_CONN_STATE_CLIENT_SENDING: return "client sending";
- case DIR_CONN_STATE_CLIENT_READING: return "client reading";
- case DIR_CONN_STATE_CLIENT_FINISHED: return "client finished";
- case DIR_CONN_STATE_SERVER_COMMAND_WAIT: return "waiting for command";
- case DIR_CONN_STATE_SERVER_WRITING: return "writing";
- }
- break;
- case CONN_TYPE_CPUWORKER:
- switch (state) {
- case CPUWORKER_STATE_IDLE: return "idle";
- case CPUWORKER_STATE_BUSY_ONION: return "busy with onion";
- }
- break;
- case CONN_TYPE_CONTROL:
- switch (state) {
- case CONTROL_CONN_STATE_OPEN: return "open (protocol v1)";
- case CONTROL_CONN_STATE_NEEDAUTH:
- return "waiting for authentication (protocol v1)";
- }
- break;
- }
- log_warn(LD_BUG, "unknown connection state %d (type %d)", state, type);
- tor_snprintf(buf, sizeof(buf),
- "unknown state [%d] on unknown [%s] connection",
- state, conn_type_to_string(type));
- return buf;
- }
- dir_connection_t *
- dir_connection_new(int socket_family)
- {
- dir_connection_t *dir_conn = tor_malloc_zero(sizeof(dir_connection_t));
- connection_init(time(NULL), TO_CONN(dir_conn), CONN_TYPE_DIR, socket_family);
- return dir_conn;
- }
- or_connection_t *
- or_connection_new(int socket_family)
- {
- or_connection_t *or_conn = tor_malloc_zero(sizeof(or_connection_t));
- time_t now = time(NULL);
- connection_init(now, TO_CONN(or_conn), CONN_TYPE_OR, socket_family);
- or_conn->timestamp_last_added_nonpadding = time(NULL);
- or_conn->next_circ_id = crypto_rand_int(1<<15);
- return or_conn;
- }
- edge_connection_t *
- edge_connection_new(int type, int socket_family)
- {
- edge_connection_t *edge_conn = tor_malloc_zero(sizeof(edge_connection_t));
- tor_assert(type == CONN_TYPE_EXIT || type == CONN_TYPE_AP);
- connection_init(time(NULL), TO_CONN(edge_conn), type, socket_family);
- if (type == CONN_TYPE_AP)
- edge_conn->socks_request = tor_malloc_zero(sizeof(socks_request_t));
- return edge_conn;
- }
- control_connection_t *
- control_connection_new(int socket_family)
- {
- control_connection_t *control_conn =
- tor_malloc_zero(sizeof(control_connection_t));
- connection_init(time(NULL),
- TO_CONN(control_conn), CONN_TYPE_CONTROL, socket_family);
- return control_conn;
- }
- connection_t *
- connection_new(int type, int socket_family)
- {
- switch (type) {
- case CONN_TYPE_OR:
- return TO_CONN(or_connection_new(socket_family));
- case CONN_TYPE_EXIT:
- case CONN_TYPE_AP:
- return TO_CONN(edge_connection_new(type, socket_family));
- case CONN_TYPE_DIR:
- return TO_CONN(dir_connection_new(socket_family));
- case CONN_TYPE_CONTROL:
- return TO_CONN(control_connection_new(socket_family));
- default: {
- connection_t *conn = tor_malloc_zero(sizeof(connection_t));
- connection_init(time(NULL), conn, type, socket_family);
- return conn;
- }
- }
- }
- static void
- connection_init(time_t now, connection_t *conn, int type, int socket_family)
- {
- static uint64_t n_connections_allocated = 1;
- switch (type) {
- case CONN_TYPE_OR:
- conn->magic = OR_CONNECTION_MAGIC;
- break;
- case CONN_TYPE_EXIT:
- case CONN_TYPE_AP:
- conn->magic = EDGE_CONNECTION_MAGIC;
- break;
- case CONN_TYPE_DIR:
- conn->magic = DIR_CONNECTION_MAGIC;
- break;
- case CONN_TYPE_CONTROL:
- conn->magic = CONTROL_CONNECTION_MAGIC;
- break;
- default:
- conn->magic = BASE_CONNECTION_MAGIC;
- break;
- }
- conn->s = -1;
- conn->conn_array_index = -1;
- conn->global_identifier = n_connections_allocated++;
- conn->type = type;
- conn->socket_family = socket_family;
- if (!connection_is_listener(conn)) {
- conn->inbuf = buf_new();
- conn->outbuf = buf_new();
- }
- conn->timestamp_created = now;
- conn->timestamp_lastread = now;
- conn->timestamp_lastwritten = now;
- }
- void
- connection_link_connections(connection_t *conn_a, connection_t *conn_b)
- {
- tor_assert(conn_a->s < 0);
- tor_assert(conn_b->s < 0);
- conn_a->linked = 1;
- conn_b->linked = 1;
- conn_a->linked_conn = conn_b;
- conn_b->linked_conn = conn_a;
- }
- static void
- _connection_free(connection_t *conn)
- {
- void *mem;
- size_t memlen;
- switch (conn->type) {
- case CONN_TYPE_OR:
- tor_assert(conn->magic == OR_CONNECTION_MAGIC);
- mem = TO_OR_CONN(conn);
- memlen = sizeof(or_connection_t);
- break;
- case CONN_TYPE_AP:
- case CONN_TYPE_EXIT:
- tor_assert(conn->magic == EDGE_CONNECTION_MAGIC);
- mem = TO_EDGE_CONN(conn);
- memlen = sizeof(edge_connection_t);
- break;
- case CONN_TYPE_DIR:
- tor_assert(conn->magic == DIR_CONNECTION_MAGIC);
- mem = TO_DIR_CONN(conn);
- memlen = sizeof(dir_connection_t);
- break;
- case CONN_TYPE_CONTROL:
- tor_assert(conn->magic == CONTROL_CONNECTION_MAGIC);
- mem = TO_CONTROL_CONN(conn);
- memlen = sizeof(control_connection_t);
- break;
- default:
- tor_assert(conn->magic == BASE_CONNECTION_MAGIC);
- mem = conn;
- memlen = sizeof(connection_t);
- break;
- }
- if (conn->linked) {
- log_info(LD_GENERAL, "Freeing linked %s connection [%s] with %d "
- "bytes on inbuf, %d on outbuf.",
- conn_type_to_string(conn->type),
- conn_state_to_string(conn->type, conn->state),
- (int)buf_datalen(conn->inbuf), (int)buf_datalen(conn->outbuf));
- }
- if (!connection_is_listener(conn)) {
- buf_free(conn->inbuf);
- buf_free(conn->outbuf);
- } else {
- if (conn->socket_family == AF_UNIX) {
-
- tor_assert(conn->type == CONN_TYPE_CONTROL_LISTENER);
- if (unlink(conn->address) < 0 && errno != ENOENT) {
- log_warn(LD_NET, "Could not unlink %s: %s", conn->address,
- strerror(errno));
- }
- }
- }
- tor_free(conn->address);
- if (connection_speaks_cells(conn)) {
- or_connection_t *or_conn = TO_OR_CONN(conn);
- if (or_conn->tls) {
- tor_tls_free(or_conn->tls);
- or_conn->tls = NULL;
- }
- if (or_conn->handshake_state) {
- or_handshake_state_free(or_conn->handshake_state);
- or_conn->handshake_state = NULL;
- }
- tor_free(or_conn->nickname);
- }
- if (CONN_IS_EDGE(conn)) {
- edge_connection_t *edge_conn = TO_EDGE_CONN(conn);
- tor_free(edge_conn->chosen_exit_name);
- if (edge_conn->socks_request) {
- memset(edge_conn->socks_request, 0xcc, sizeof(socks_request_t));
- tor_free(edge_conn->socks_request);
- }
- if (edge_conn->rend_data)
- rend_data_free(edge_conn->rend_data);
- }
- if (conn->type == CONN_TYPE_CONTROL) {
- control_connection_t *control_conn = TO_CONTROL_CONN(conn);
- tor_free(control_conn->incoming_cmd);
- }
- tor_free(conn->read_event);
- tor_free(conn->write_event);
- if (conn->type == CONN_TYPE_DIR) {
- dir_connection_t *dir_conn = TO_DIR_CONN(conn);
- tor_free(dir_conn->requested_resource);
- if (dir_conn->zlib_state)
- tor_zlib_free(dir_conn->zlib_state);
- if (dir_conn->fingerprint_stack) {
- SMARTLIST_FOREACH(dir_conn->fingerprint_stack, char *, cp, tor_free(cp));
- smartlist_free(dir_conn->fingerprint_stack);
- }
- if (dir_conn->cached_dir)
- cached_dir_decref(dir_conn->cached_dir);
- if (dir_conn->rend_data)
- rend_data_free(dir_conn->rend_data);
- }
- if (conn->s >= 0) {
- log_debug(LD_NET,"closing fd %d.",conn->s);
- tor_close_socket(conn->s);
- conn->s = -1;
- }
- if (conn->type == CONN_TYPE_OR &&
- !tor_digest_is_zero(TO_OR_CONN(conn)->identity_digest)) {
- log_warn(LD_BUG, "called on OR conn with non-zeroed identity_digest");
- connection_or_remove_from_identity_map(TO_OR_CONN(conn));
- }
- memset(conn, 0xAA, memlen);
- tor_free(mem);
- }
- void
- connection_free(connection_t *conn)
- {
- tor_assert(conn);
- tor_assert(!connection_is_on_closeable_list(conn));
- tor_assert(!connection_in_array(conn));
- if (conn->linked_conn) {
- log_err(LD_BUG, "Called with conn->linked_conn still set.");
- tor_fragile_assert();
- conn->linked_conn->linked_conn = NULL;
- if (! conn->linked_conn->marked_for_close &&
- conn->linked_conn->reading_from_linked_conn)
- connection_start_reading(conn->linked_conn);
- conn->linked_conn = NULL;
- }
- if (connection_speaks_cells(conn)) {
- if (!tor_digest_is_zero(TO_OR_CONN(conn)->identity_digest)) {
- connection_or_remove_from_identity_map(TO_OR_CONN(conn));
- }
- }
- if (conn->type == CONN_TYPE_CONTROL) {
- TO_CONTROL_CONN(conn)->event_mask = 0;
- control_update_global_event_mask();
- }
- connection_unregister_events(conn);
- _connection_free(conn);
- }
- void
- connection_free_all(void)
- {
- smartlist_t *conns = get_connection_array();
-
- SMARTLIST_FOREACH(conns, connection_t *, conn,
- if (conn->type == CONN_TYPE_CONTROL)
- TO_CONTROL_CONN(conn)->event_mask = 0);
- control_update_global_event_mask();
-
- connection_or_clear_identity_map();
- SMARTLIST_FOREACH(conns, connection_t *, conn, _connection_free(conn));
- if (outgoing_addrs) {
- SMARTLIST_FOREACH(outgoing_addrs, void*, addr, tor_free(addr));
- smartlist_free(outgoing_addrs);
- outgoing_addrs = NULL;
- }
- }
- void
- connection_about_to_close_connection(connection_t *conn)
- {
- circuit_t *circ;
- dir_connection_t *dir_conn;
- or_connection_t *or_conn;
- edge_connection_t *edge_conn;
- time_t now = time(NULL);
- tor_assert(conn->marked_for_close);
- if (CONN_IS_EDGE(conn)) {
- edge_conn = TO_EDGE_CONN(conn);
- if (!edge_conn->edge_has_sent_end) {
- log_warn(LD_BUG, "(Harmless.) Edge connection (marked at %s:%d) "
- "hasn't sent end yet?",
- conn->marked_for_close_file, conn->marked_for_close);
- tor_fragile_assert();
- }
- }
- switch (conn->type) {
- case CONN_TYPE_DIR:
- dir_conn = TO_DIR_CONN(conn);
- if (conn->state < DIR_CONN_STATE_CLIENT_FINISHED) {
-
- connection_dir_request_failed(dir_conn);
- }
-
- if (conn->purpose == DIR_PURPOSE_FETCH_RENDDESC_V2 &&
- dir_conn->rend_data &&
- strlen(dir_conn->rend_data->onion_address) ==
- REND_SERVICE_ID_LEN_BASE32)
- rend_client_refetch_v2_renddesc(dir_conn->rend_data);
- break;
- case CONN_TYPE_OR:
- or_conn = TO_OR_CONN(conn);
-
- if (conn->state != OR_CONN_STATE_OPEN) {
-
- circuit_n_conn_done(TO_OR_CONN(conn), 0);
-
- if (connection_or_nonopen_was_started_here(or_conn)) {
- or_options_t *options = get_options();
- rep_hist_note_connect_failed(or_conn->identity_digest, now);
- entry_guard_register_connect_status(or_conn->identity_digest,0,
- !options->HttpsProxy, now);
- if (conn->state >= OR_CONN_STATE_TLS_HANDSHAKING) {
- int reason = tls_error_to_orconn_end_reason(or_conn->tls_error);
- control_event_or_conn_status(or_conn, OR_CONN_EVENT_FAILED,
- reason);
- if (!authdir_mode_tests_reachability(options))
- control_event_bootstrap_problem(
- orconn_end_reason_to_control_string(reason), reason);
- }
- }
- } else if (conn->hold_open_until_flushed) {
-
- rep_hist_note_disconnect(or_conn->identity_digest, now);
- control_event_or_conn_status(or_conn, OR_CONN_EVENT_CLOSED,
- tls_error_to_orconn_end_reason(or_conn->tls_error));
- } else if (or_conn->identity_digest) {
- rep_hist_note_connection_died(or_conn->identity_digest, now);
- control_event_or_conn_status(or_conn, OR_CONN_EVENT_CLOSED,
- tls_error_to_orconn_end_reason(or_conn->tls_error));
- }
-
- circuit_unlink_all_from_or_conn(TO_OR_CONN(conn),
- END_CIRC_REASON_OR_CONN_CLOSED);
- break;
- case CONN_TYPE_AP:
- edge_conn = TO_EDGE_CONN(conn);
- if (edge_conn->socks_request->has_finished == 0) {
-
- log_warn(LD_BUG,"Closing stream (marked at %s:%d) without sending"
- " back a socks reply.",
- conn->marked_for_close_file, conn->marked_for_close);
- }
- if (!edge_conn->end_reason) {
- log_warn(LD_BUG,"Closing stream (marked at %s:%d) without having"
- " set end_reason.",
- conn->marked_for_close_file, conn->marked_for_close);
- }
- if (edge_conn->dns_server_request) {
- log_warn(LD_BUG,"Closing stream (marked at %s:%d) without having"
- " replied to DNS request.",
- conn->marked_for_close_file, conn->marked_for_close);
- dnsserv_reject_request(edge_conn);
- }
- control_event_stream_bandwidth(edge_conn);
- control_event_stream_status(edge_conn, STREAM_EVENT_CLOSED,
- edge_conn->end_reason);
- circ = circuit_get_by_edge_conn(edge_conn);
- if (circ)
- circuit_detach_stream(circ, edge_conn);
- break;
- case CONN_TYPE_EXIT:
- edge_conn = TO_EDGE_CONN(conn);
- circ = circuit_get_by_edge_conn(edge_conn);
- if (circ)
- circuit_detach_stream(circ, edge_conn);
- if (conn->state == EXIT_CONN_STATE_RESOLVING) {
- connection_dns_remove(edge_conn);
- }
- break;
- }
- }
- #define CONN_IS_CLOSED(c) \
- ((c)->linked ? ((c)->linked_conn_is_closed) : ((c)->s < 0))
- void
- connection_close_immediate(connection_t *conn)
- {
- assert_connection_ok(conn,0);
- if (CONN_IS_CLOSED(conn)) {
- log_err(LD_BUG,"Attempt to close already-closed connection.");
- tor_fragile_assert();
- return;
- }
- if (conn->outbuf_flushlen) {
- log_info(LD_NET,"fd %d, type %s, state %s, %d bytes on outbuf.",
- conn->s, conn_type_to_string(conn->type),
- conn_state_to_string(conn->type, conn->state),
- (int)conn->outbuf_flushlen);
- }
- connection_unregister_events(conn);
- if (conn->s >= 0)
- tor_close_socket(conn->s);
- conn->s = -1;
- if (conn->linked)
- conn->linked_conn_is_closed = 1;
- if (!connection_is_listener(conn)) {
- buf_clear(conn->outbuf);
- conn->outbuf_flushlen = 0;
- }
- }
- void
- _connection_mark_for_close(connection_t *conn, int line, const char *file)
- {
- assert_connection_ok(conn,0);
- tor_assert(line);
- tor_assert(line < 1<<16);
- tor_assert(file);
- if (conn->marked_for_close) {
- log(LOG_WARN,LD_BUG,"Duplicate call to connection_mark_for_close at %s:%d"
- " (first at %s:%d)", file, line, conn->marked_for_close_file,
- conn->marked_for_close);
- tor_fragile_assert();
- return;
- }
- conn->marked_for_close = line;
- conn->marked_for_close_file = file;
- add_connection_to_closeable_list(conn);
-
- conn->timestamp_lastwritten = time(NULL);
- }
- void
- connection_expire_held_open(void)
- {
- time_t now;
- smartlist_t *conns = get_connection_array();
- now = time(NULL);
- SMARTLIST_FOREACH(conns, connection_t *, conn,
- {
-
- if (conn->hold_open_until_flushed) {
- tor_assert(conn->marked_for_close);
- if (now - conn->timestamp_lastwritten >= 15) {
- int severity;
- if (conn->type == CONN_TYPE_EXIT ||
- (conn->type == CONN_TYPE_DIR &&
- conn->purpose == DIR_PURPOSE_SERVER))
- severity = LOG_INFO;
- else
- severity = LOG_NOTICE;
- log_fn(severity, LD_NET,
- "Giving up on marked_for_close conn that's been flushing "
- "for 15s (fd %d, type %s, state %s).",
- conn->s, conn_type_to_string(conn->type),
- conn_state_to_string(conn->type, conn->state));
- conn->hold_open_until_flushed = 0;
- }
- }
- });
- }
- static struct sockaddr_in *
- create_inet_sockaddr(const char *listenaddress, uint16_t listenport,
- char **readable_address, socklen_t *socklen_out) {
- struct sockaddr_in *listenaddr = NULL;
- uint32_t addr;
- uint16_t usePort = 0;
- if (parse_addr_port(LOG_WARN,
- listenaddress, readable_address, &addr, &usePort)<0) {
- log_warn(LD_CONFIG,
- "Error parsing/resolving ListenAddress %s", listenaddress);
- goto err;
- }
- if (usePort==0)
- usePort = listenport;
- listenaddr = tor_malloc_zero(sizeof(struct sockaddr_in));
- listenaddr->sin_addr.s_addr = htonl(addr);
- listenaddr->sin_family = AF_INET;
- listenaddr->sin_port = htons((uint16_t) usePort);
- *socklen_out = sizeof(struct sockaddr_in);
- return listenaddr;
- err:
- tor_free(listenaddr);
- return NULL;
- }
- #ifdef HAVE_SYS_UN_H
- static struct sockaddr_un *
- create_unix_sockaddr(const char *listenaddress, char **readable_address,
- socklen_t *len_out)
- {
- struct sockaddr_un *sockaddr = NULL;
- sockaddr = tor_malloc_zero(sizeof(struct sockaddr_un));
- sockaddr->sun_family = AF_UNIX;
- strncpy(sockaddr->sun_path, listenaddress, sizeof(sockaddr->sun_path));
- if (readable_address)
- *readable_address = tor_strdup(listenaddress);
- *len_out = sizeof(struct sockaddr_un);
- return sockaddr;
- }
- #else
- static struct sockaddr *
- create_unix_sockaddr(const char *listenaddress, char **readable_address,
- socklen_t *len_out)
- {
- (void)listenaddress;
- (void)readable_address;
- log_fn(LOG_ERR, LD_BUG,
- "Unix domain sockets not supported, yet we tried to create one.");
- *len_out = 0;
- tor_assert(0);
- };
- #endif
- static void
- warn_too_many_conns(void)
- {
- #define WARN_TOO_MANY_CONNS_INTERVAL (6*60*60)
- static time_t last_warned = 0;
- time_t now = time(NULL);
- int n_conns = get_n_open_sockets();
- if (last_warned + WARN_TOO_MANY_CONNS_INTERVAL < now) {
- log_warn(LD_NET,"Failing because we have %d connections already. Please "
- "raise your ulimit -n.", n_conns);
- last_warned = now;
- }
- control_event_general_status(LOG_WARN, "TOO_MANY_CONNECTIONS CURRENT=%d",
- n_conns);
- }
- static connection_t *
- connection_create_listener(struct sockaddr *listensockaddr, socklen_t socklen,
- int type, char* address)
- {
- connection_t *conn;
- int s;
- uint16_t usePort = 0;
- int start_reading = 0;
- if (get_n_open_sockets() >= get_options()->_ConnLimit-1) {
- warn_too_many_conns();
- return NULL;
- }
- if (listensockaddr->sa_family == AF_INET) {
- int is_tcp = (type != CONN_TYPE_AP_DNS_LISTENER);
- #ifndef MS_WINDOWS
- int one=1;
- #endif
- if (is_tcp)
- start_reading = 1;
- usePort = ntohs( (uint16_t)
- ((struct sockaddr_in *)listensockaddr)->sin_port);
- log_notice(LD_NET, "Opening %s on %s:%d",
- conn_type_to_string(type), address, usePort);
- s = tor_open_socket(PF_INET,
- is_tcp ? SOCK_STREAM : SOCK_DGRAM,
- is_tcp ? IPPROTO_TCP: IPPROTO_UDP);
- if (s < 0) {
- log_warn(LD_NET,"Socket creation failed.");
- goto err;
- }
- #ifndef MS_WINDOWS
-
- setsockopt(s, SOL_SOCKET, SO_REUSEADDR, (void*) &one,
- (socklen_t)sizeof(one));
- #endif
- if (bind(s,listensockaddr,socklen) < 0) {
- const char *helpfulhint = "";
- int e = tor_socket_errno(s);
- if (ERRNO_IS_EADDRINUSE(e))
- helpfulhint = ". Is Tor already running?";
- log_warn(LD_NET, "Could not bind to %s:%u: %s%s", address, usePort,
- tor_socket_strerror(e), helpfulhint);
- tor_close_socket(s);
- goto err;
- }
- if (is_tcp) {
- if (listen(s,SOMAXCONN) < 0) {
- log_warn(LD_NET, "Could not listen on %s:%u: %s", address, usePort,
- tor_socket_strerror(tor_socket_errno(s)));
- tor_close_socket(s);
- goto err;
- }
- }
- #ifdef HAVE_SYS_UN_H
- } else if (listensockaddr->sa_family == AF_UNIX) {
- start_reading = 1;
-
- tor_assert(type == CONN_TYPE_CONTROL_LISTENER);
- log_notice(LD_NET, "Opening %s on %s",
- conn_type_to_string(type), address);
- if (unlink(address) < 0 && errno != ENOENT) {
- log_warn(LD_NET, "Could not unlink %s: %s", address,
- strerror(errno));
- goto err;
- }
- s = tor_open_socket(AF_UNIX, SOCK_STREAM, 0);
- if (s < 0) {
- log_warn(LD_NET,"Socket creation failed: %s.", strerror(errno));
- goto err;
- }
- if (bind(s, listensockaddr, (socklen_t)sizeof(struct sockaddr_un)) == -1) {
- log_warn(LD_NET,"Bind to %s failed: %s.", address,
- tor_socket_strerror(tor_socket_errno(s)));
- goto err;
- }
- if (listen(s,SOMAXCONN) < 0) {
- log_warn(LD_NET, "Could not listen on %s: %s", address,
- tor_socket_strerror(tor_socket_errno(s)));
- tor_close_socket(s);
- goto err;
- }
- #endif
- } else {
- log_err(LD_BUG,"Got unexpected address family %d.",
- listensockaddr->sa_family);
- tor_assert(0);
- }
- set_socket_nonblocking(s);
- conn = connection_new(type, listensockaddr->sa_family);
- conn->socket_family = listensockaddr->sa_family;
- conn->s = s;
- conn->address = tor_strdup(address);
- conn->port = usePort;
- if (connection_add(conn) < 0) {
- log_warn(LD_NET,"connection_add for listener failed. Giving up.");
- connection_free(conn);
- goto err;
- }
- log_debug(LD_NET,"%s listening on port %u.",
- conn_type_to_string(type), usePort);
- conn->state = LISTENER_STATE_READY;
- if (start_reading) {
- connection_start_reading(conn);
- } else {
- tor_assert(type == CONN_TYPE_AP_DNS_LISTENER);
- dnsserv_configure_listener(conn);
- }
- return conn;
- err:
- return NULL;
- }
- static int
- check_sockaddr(struct sockaddr *sa, int len, int level)
- {
- int ok = 1;
- if (sa->sa_family == AF_INET) {
- struct sockaddr_in *sin=(struct sockaddr_in*)sa;
- if (len != sizeof(struct sockaddr_in)) {
- log_fn(level, LD_NET, "Length of address not as expected: %d vs %d",
- len,(int)sizeof(struct sockaddr_in));
- ok = 0;
- }
- if (sin->sin_addr.s_addr == 0 || sin->sin_port == 0) {
- log_fn(level, LD_NET,
- "Address for new connection has address/port equal to zero.");
- ok = 0;
- }
- } else if (sa->sa_family == AF_INET6) {
- struct sockaddr_in6 *sin6=(struct sockaddr_in6*)sa;
- if (len != sizeof(struct sockaddr_in6)) {
- log_fn(level, LD_NET, "Length of address not as expected: %d vs %d",
- len,(int)sizeof(struct sockaddr_in6));
- ok = 0;
- }
- if (tor_mem_is_zero((void*)sin6->sin6_addr.s6_addr, 16) ||
- sin6->sin6_port == 0) {
- log_fn(level, LD_NET,
- "Address for new connection has address/port equal to zero.");
- ok = 0;
- }
- } else {
- ok = 0;
- }
- return ok ? 0 : -1;
- }
- static int
- check_sockaddr_family_match(sa_family_t got, connection_t *listener)
- {
- if (got != listener->socket_family) {
- log_info(LD_BUG, "A listener connection returned a socket with a "
- "mismatched family. %s for addr_family %d gave us a socket "
- "with address family %d. Dropping.",
- conn_type_to_string(listener->type),
- (int)listener->socket_family,
- (int)got);
- return -1;
- }
- return 0;
- }
- static int
- connection_handle_listener_read(connection_t *conn, int new_type)
- {
- int news;
- connection_t *newconn;
-
- char addrbuf[256];
- struct sockaddr *remote = (struct sockaddr*)addrbuf;
-
- socklen_t remotelen = (socklen_t)sizeof(addrbuf);
- or_options_t *options = get_options();
- tor_assert((size_t)remotelen >= sizeof(struct sockaddr_in));
- memset(addrbuf, 0, sizeof(addrbuf));
- news = tor_accept_socket(conn->s,remote,&remotelen);
- if (news < 0) {
- int e = tor_socket_errno(conn->s);
- if (ERRNO_IS_ACCEPT_EAGAIN(e)) {
- return 0;
- } else if (ERRNO_IS_ACCEPT_RESOURCE_LIMIT(e)) {
- warn_too_many_conns();
- return 0;
- }
-
- log_warn(LD_NET,"accept() failed: %s. Closing listener.",
- tor_socket_strerror(e));
- connection_mark_for_close(conn);
- return -1;
- }
- log_debug(LD_NET,
- "Connection accepted on socket %d (child of fd %d).",
- news,conn->s);
- set_socket_nonblocking(news);
- if (options->ConstrainedSockets)
- set_constrained_socket_buffers(news, (int)options->ConstrainedSockSize);
- if (check_sockaddr_family_match(remote->sa_family, conn) < 0) {
- tor_close_socket(news);
- return 0;
- }
- if (conn->socket_family == AF_INET || conn->socket_family == AF_INET6) {
- tor_addr_t addr;
- uint16_t port;
- if (check_sockaddr(remote, remotelen, LOG_INFO)<0) {
- log_info(LD_NET,
- "accept() returned a strange address; trying getsockname().");
- remotelen=sizeof(addrbuf);
- memset(addrbuf, 0, sizeof(addrbuf));
- if (getsockname(news, remote, &remotelen)<0) {
- int e = tor_socket_errno(news);
- log_warn(LD_NET, "getsockname() for new connection failed: %s",
- tor_socket_strerror(e));
- } else {
- if (check_sockaddr((struct sockaddr*)addrbuf, remotelen,
- LOG_WARN) < 0) {
- log_warn(LD_NET,"Something's wrong with this conn. Closing it.");
- tor_close_socket(news);
- return 0;
- }
- }
- }
- if (check_sockaddr_family_match(remote->sa_family, conn) < 0) {
- tor_close_socket(news);
- return 0;
- }
- tor_addr_from_sockaddr(&addr, remote, &port);
-
- if (new_type == CONN_TYPE_AP) {
-
- if (socks_policy_permits_address(&addr) == 0) {
- log_notice(LD_APP,
- "Denying socks connection from untrusted address %s.",
- fmt_addr(&addr));
- tor_close_socket(news);
- return 0;
- }
- }
- if (new_type == CONN_TYPE_DIR) {
-
- if (dir_policy_permits_address(&addr) == 0) {
- log_notice(LD_DIRSERV,"Denying dir connection from address %s.",
- fmt_addr(&addr));
- tor_close_socket(news);
- return 0;
- }
- }
- newconn = connection_new(new_type, conn->socket_family);
- newconn->s = news;
-
- tor_addr_copy(&newconn->addr, &addr);
- newconn->port = port;
- newconn->address = tor_dup_addr(&addr);
- } else if (conn->socket_family == AF_UNIX) {
-
- tor_assert(conn->type == CONN_TYPE_CONTROL_LISTENER);
- newconn = connection_new(new_type, conn->socket_family);
- newconn->s = news;
-
- tor_addr_make_unspec(&newconn->addr);
- newconn->port = 1;
- newconn->address = tor_strdup(conn->address);
- } else {
- tor_assert(0);
- };
- if (connection_add(newconn) < 0) {
- connection_free(newconn);
- return 0;
- }
- if (connection_init_accepted_conn(newconn, conn->type) < 0) {
- connection_mark_for_close(newconn);
- return 0;
- }
- return 0;
- }
- static int
- connection_init_accepted_conn(connection_t *conn, uint8_t listener_type)
- {
- connection_start_reading(conn);
- switch (conn->type) {
- case CONN_TYPE_OR:
- control_event_or_conn_status(TO_OR_CONN(conn), OR_CONN_EVENT_NEW, 0);
- return connection_tls_start_handshake(TO_OR_CONN(conn), 1);
- case CONN_TYPE_AP:
- switch (listener_type) {
- case CONN_TYPE_AP_LISTENER:
- conn->state = AP_CONN_STATE_SOCKS_WAIT;
- break;
- case CONN_TYPE_AP_TRANS_LISTENER:
- conn->state = AP_CONN_STATE_CIRCUIT_WAIT;
- return connection_ap_process_transparent(TO_EDGE_CONN(conn));
- case CONN_TYPE_AP_NATD_LISTENER:
- conn->state = AP_CONN_STATE_NATD_WAIT;
- break;
- }
- break;
- case CONN_TYPE_DIR:
- conn->purpose = DIR_PURPOSE_SERVER;
- conn->state = DIR_CONN_STATE_SERVER_COMMAND_WAIT;
- break;
- case CONN_TYPE_CONTROL:
- conn->state = CONTROL_CONN_STATE_NEEDAUTH;
- break;
- }
- return 0;
- }
- int
- connection_connect(connection_t *conn, const char *address,
- const tor_addr_t *addr, uint16_t port, int *socket_error)
- {
- int s, inprogress = 0;
- char addrbuf[256];
- struct sockaddr *dest_addr = (struct sockaddr*) addrbuf;
- socklen_t dest_addr_len;
- or_options_t *options = get_options();
- int protocol_family;
- if (get_n_open_sockets() >= get_options()->_ConnLimit-1) {
- warn_too_many_conns();
- return -1;
- }
- if (tor_addr_family(addr) == AF_INET6)
- protocol_family = PF_INET6;
- else
- protocol_family = PF_INET;
- s = tor_open_socket(protocol_family,SOCK_STREAM,IPPROTO_TCP);
- if (s < 0) {
- *socket_error = tor_socket_errno(-1);
- log_warn(LD_NET,"Error creating network socket: %s",
- tor_socket_strerror(*socket_error));
- return -1;
- }
- if (options->OutboundBindAddress) {
- struct sockaddr_in ext_addr;
- memset(&ext_addr, 0, sizeof(ext_addr));
- ext_addr.sin_family = AF_INET;
- ext_addr.sin_port = 0;
- if (!tor_inet_aton(options->OutboundBindAddress, &ext_addr.sin_addr)) {
- log_warn(LD_CONFIG,"Outbound bind address '%s' didn't parse. Ignoring.",
- options->OutboundBindAddress);
- } else {
- if (bind(s, (struct sockaddr*)&ext_addr,
- (socklen_t)sizeof(ext_addr)) < 0) {
- *socket_error = tor_socket_errno(s);
- log_warn(LD_NET,"Error binding network socket: %s",
- tor_socket_strerror(*socket_error));
- tor_close_socket(s);
- return -1;
- }
- }
- }
- set_socket_nonblocking(s);
- if (options->ConstrainedSockets)
- set_constrained_socket_buffers(s, (int)options->ConstrainedSockSize);
- memset(addrbuf,0,sizeof(addrbuf));
- dest_addr = (struct sockaddr*) addrbuf;
- dest_addr_len = tor_addr_to_sockaddr(addr, port, dest_addr, sizeof(addrbuf));
- tor_assert(dest_addr_len > 0);
- log_debug(LD_NET,"Connecting to %s:%u.",escaped_safe_str(address),port);
- if (connect(s, dest_addr, dest_addr_len) < 0) {
- int e = tor_socket_errno(s);
- if (!ERRNO_IS_CONN_EINPROGRESS(e)) {
-
- *socket_error = e;
- log_info(LD_NET,
- "connect() to %s:%u failed: %s",escaped_safe_str(address),
- port, tor_socket_strerror(e));
- tor_close_socket(s);
- return -1;
- } else {
- inprogress = 1;
- }
- }
- if (!server_mode(options))
- client_check_address_changed(s);
-
- log_fn(inprogress?LOG_DEBUG:LOG_INFO, LD_NET,
- "Connection to %s:%u %s (sock %d).",escaped_safe_str(address),
- port, inprogress?"in progress":"established", s);
- conn->s = s;
- if (connection_add(conn) < 0)
- return -1;
- return inprogress ? 0 : 1;
- }
- static const char *
- connection_proxy_state_to_string(int state)
- {
- static const char *unknown = "???";
- static const char *states[] = {
- "PROXY_NONE",
- "PROXY_HTTPS_WANT_CONNECT_OK",
- "PROXY_SOCKS4_WANT_CONNECT_OK",
- "PROXY_SOCKS5_WANT_AUTH_METHOD_NONE",
- "PROXY_SOCKS5_WANT_AUTH_METHOD_RFC1929",
- "PROXY_SOCKS5_WANT_AUTH_RFC1929_OK",
- "PROXY_SOCKS5_WANT_CONNECT_OK",
- "PROXY_CONNECTED",
- };
- if (state < PROXY_NONE || state > PROXY_CONNECTED)
- return unknown;
- return states[state];
- }
- int
- connection_proxy_connect(connection_t *conn, int type)
- {
- or_options_t *options;
- tor_assert(conn);
- options = get_options();
- switch (type) {
- case PROXY_CONNECT: {
- char buf[1024];
- char *base64_authenticator=NULL;
- const char *authenticator = options->HttpsProxyAuthenticator;
-
- if (authenticator) {
- base64_authenticator = alloc_http_authenticator(authenticator);
- if (!base64_authenticator)
- log_warn(LD_OR, "Encoding https authenticator failed");
- }
- if (base64_authenticator) {
- tor_snprintf(buf, sizeof(buf), "CONNECT %s:%d HTTP/1.1\r\n"
- "Proxy-Authorization: Basic %s\r\n\r\n",
- fmt_addr(&conn->addr),
- conn->port, base64_authenticator);
- tor_free(base64_authenticator);
- } else {
- tor_snprintf(buf, sizeof(buf), "CONNECT %s:%d HTTP/1.0\r\n\r\n",
- fmt_addr(&conn->addr), conn->port);
- }
- connection_write_to_buf(buf, strlen(buf), conn);
- conn->proxy_state = PROXY_HTTPS_WANT_CONNECT_OK;
- break;
- }
- case PROXY_SOCKS4: {
- unsigned char buf[9];
- uint16_t portn;
- uint32_t ip4addr;
-
- if (tor_addr_family(&conn->addr) != AF_INET) {
- log_warn(LD_NET, "SOCKS4 client is incompatible with with IPv6");
- return -1;
- }
- ip4addr = tor_addr_to_ipv4n(&conn->addr);
- portn = htons(conn->port);
- buf[0] = 4;
- buf[1] = SOCKS_COMMAND_CONNECT;
- memcpy(buf + 2, &portn, 2);
- memcpy(buf + 4, &ip4addr, 4);
- buf[8] = 0;
- connection_write_to_buf((char *)buf, sizeof(buf), conn);
- conn->proxy_state = PROXY_SOCKS4_WANT_CONNECT_OK;
- break;
- }
- case PROXY_SOCKS5: {
- unsigned char buf[4];
-
- buf[0] = 5;
-
- if (options->Socks5ProxyUsername) {
- buf[1] = 2;
- buf[2] = 0x00;
- buf[3] = 0x02;
- conn->proxy_state = PROXY_SOCKS5_WANT_AUTH_METHOD_RFC1929;
- } else {
- buf[1] = 1;
- buf[2] = 0x00;
- conn->proxy_state = PROXY_SOCKS5_WANT_AUTH_METHOD_NONE;
- }
- connection_write_to_buf((char *)buf, 2 + buf[1], conn);
- break;
- }
- default:
- log_err(LD_BUG, "Invalid proxy protocol, %d", type);
- tor_fragile_assert();
- return -1;
- }
- log_debug(LD_NET, "set state %s",
- connection_proxy_state_to_string(conn->proxy_state));
- return 0;
- }
- static int
- connection_read_https_proxy_response(connection_t *conn)
- {
- char *headers;
- char *reason=NULL;
- int status_code;
- time_t date_header;
- switch (fetch_from_buf_http(conn->inbuf,
- &headers, MAX_HEADERS_SIZE,
- NULL, NULL, 10000, 0)) {
- case -1:
- log_warn(LD_PROTOCOL,
- "Your https proxy sent back an oversized response. Closing.");
- return -1;
- case 0:
- log_info(LD_NET,"https proxy response not all here yet. Waiting.");
- return 0;
-
- }
- if (parse_http_response(headers, &status_code, &date_header,
- NULL, &reason) < 0) {
- log_warn(LD_NET,
- "Unparseable headers from proxy (connecting to '%s'). Closing.",
- conn->address);
- tor_free(headers);
- return -1;
- }
- if (!reason) reason = tor_strdup("[no reason given]");
- if (status_code == 200) {
- log_info(LD_NET,
- "HTTPS connect to '%s' successful! (200 %s) Starting TLS.",
- conn->address, escaped(reason));
- tor_free(reason);
- return 1;
- }
-
- log_warn(LD_NET,
- "The https proxy sent back an unexpected status code %d (%s). "
- "Closing.",
- status_code, escaped(reason));
- tor_free(reason);
- return -1;
- }
- static void
- connection_send_socks5_connect(connection_t *conn)
- {
- unsigned char buf[1024];
- size_t reqsize = 6;
- uint16_t port = htons(conn->port);
- buf[0] = 5;
- buf[1] = SOCKS_COMMAND_CONNECT;
- buf[2] = 0;
- if (tor_addr_family(&conn->addr) == AF_INET) {
- uint32_t addr = tor_addr_to_ipv4n(&conn->addr);
- buf[3] = 1;
- reqsize += 4;
- memcpy(buf + 4, &addr, 4);
- memcpy(buf + 8, &port, 2);
- } else {
- buf[3] = 4;
- reqsize += 16;
- memcpy(buf + 4, tor_addr_to_in6(&conn->addr), 16);
- memcpy(buf + 20, &port, 2);
- }
- connection_write_to_buf((char *)buf, reqsize, conn);
- conn->proxy_state = PROXY_SOCKS5_WANT_CONNECT_OK;
- }
- int
- connection_read_proxy_handshake(connection_t *conn)
- {
- int ret = 0;
- char *reason = NULL;
- log_debug(LD_NET, "enter state %s",
- connection_proxy_state_to_string(conn->proxy_state));
- switch (conn->proxy_state) {
- case PROXY_HTTPS_WANT_CONNECT_OK:
- ret = connection_read_https_proxy_response(conn);
- if (ret == 1)
- conn->proxy_state = PROXY_CONNECTED;
- break;
- case PROXY_SOCKS4_WANT_CONNECT_OK:
- ret = fetch_from_buf_socks_client(conn->inbuf,
- conn->proxy_state,
- &reason);
- if (ret == 1)
- conn->proxy_state = PROXY_CONNECTED;
- break;
- case PROXY_SOCKS5_WANT_AUTH_METHOD_NONE:
- ret = fetch_from_buf_socks_client(conn->inbuf,
- conn->proxy_state,
- &reason);
-
- if (ret == 1) {
- connection_send_socks5_connect(conn);
- ret = 0;
- }
- break;
- case PROXY_SOCKS5_WANT_AUTH_METHOD_RFC1929:
- ret = fetch_from_buf_socks_client(conn->inbuf,
- conn->proxy_state,
- &reason);
-
- if (ret == 1) {
- connection_send_socks5_connect(conn);
- ret = 0;
- } else if (ret == 2) {
- unsigned char buf[1024];
- size_t reqsize, usize, psize;
- const char *user, *pass;
- user = get_options()->Socks5ProxyUsername;
- pass = get_options()->Socks5ProxyPassword;
- tor_assert(user && pass);
-
- usize = strlen(user);
- psize = strlen(pass);
- tor_assert(usize <= 255 && psize <= 255);
- reqsize = 3 + usize + psize;
- buf[0] = 1;
- buf[1] = usize;
- memcpy(buf + 2, user, usize);
- buf[2 + usize] = psize;
- memcpy(buf + 3 + usize, pass, psize);
- connection_write_to_buf((char *)buf, reqsize, conn);
- conn->proxy_state = PROXY_SOCKS5_WANT_AUTH_RFC1929_OK;
- ret = 0;
- }
- break;
- case PROXY_SOCKS5_WANT_AUTH_RFC1929_OK:
- ret = fetch_from_buf_socks_client(conn->inbuf,
- conn->proxy_state,
- &reason);
-
- if (ret == 1) {
- connection_send_socks5_connect(conn);
- ret = 0;
- }
- break;
- case PROXY_SOCKS5_WANT_CONNECT_OK:
- ret = fetch_from_buf_socks_client(conn->inbuf,
- conn->proxy_state,
- &reason);
- if (ret == 1)
- conn->proxy_state = PROXY_CONNECTED;
- break;
- default:
- log_err(LD_BUG, "Invalid proxy_state for reading, %d",
- conn->proxy_state);
- tor_fragile_assert();
- ret = -1;
- break;
- }
- log_debug(LD_NET, "leaving state %s",
- connection_proxy_state_to_string(conn->proxy_state));
- if (ret < 0) {
- if (reason) {
- log_warn(LD_NET, "Proxy Client: unable to connect to %s:%d (%s)",
- conn->address, conn->port, escaped(reason));
- tor_free(reason);
- } else {
- log_warn(LD_NET, "Proxy Client: unable to connect to %s:%d",
- conn->address, conn->port);
- }
- } else if (ret == 1) {
- log_info(LD_NET, "Proxy Client: connection to %s:%d successful",
- conn->address, conn->port);
- }
- return ret;
- }
- static int
- retry_listeners(int type, config_line_t *cfg,
- int port_option, const char *default_addr,
- smartlist_t *replaced_conns,
- smartlist_t *new_conns,
- int disable_all_conns,
- int socket_family)
- {
- smartlist_t *launch = smartlist_create(), *conns;
- int free_launch_elts = 1;
- int r;
- config_line_t *c;
- connection_t *conn;
- config_line_t *line;
- tor_assert(socket_family == AF_INET || socket_family == AF_UNIX);
- if (cfg && port_option) {
- for (c = cfg; c; c = c->next) {
- smartlist_add(launch, c);
- }
- free_launch_elts = 0;
- } else if (port_option) {
- line = tor_malloc_zero(sizeof(config_line_t));
- line->key = tor_strdup("");
- line->value = tor_strdup(default_addr);
- smartlist_add(launch, line);
- }
-
- conns = get_connection_array();
- SMARTLIST_FOREACH(conns, connection_t *, conn,
- {
- if (conn->type != type ||
- conn->socket_family != socket_family ||
- conn->marked_for_close)
- continue;
-
- line = NULL;
- SMARTLIST_FOREACH(launch, config_line_t *, wanted,
- {
- char *address=NULL;
- uint16_t port;
- switch (socket_family) {
- case AF_INET:
- if (!parse_addr_port(LOG_WARN,
- wanted->value, &address, NULL, &port)) {
- int addr_matches = !strcasecmp(address, conn->address);
- tor_free(address);
- if (! port)
- port = port_option;
- if (port == conn->port && addr_matches) {
- line = wanted;
- break;
- }
- }
- break;
- case AF_UNIX:
- if (!strcasecmp(wanted->value, conn->address)) {
- line = wanted;
- break;
- }
- break;
- default:
- tor_assert(0);
- }
- });
- if (!line || disable_all_conns) {
-
- log_notice(LD_NET, "Closing no-longer-configured %s on %s:%d",
- conn_type_to_string(type), conn->address, conn->port);
- if (replaced_conns) {
- smartlist_add(replaced_conns, conn);
- } else {
- connection_close_immediate(conn);
- connection_mark_for_close(conn);
- }
- } else {
-
- smartlist_remove(launch, line);
- if (free_launch_elts)
- config_free_lines(line);
- }
- });
-
- r = 0;
- if (!disable_all_conns) {
- SMARTLIST_FOREACH_BEGIN(launch, config_line_t *, cfg_line) {
- char *address = NULL;
- struct sockaddr *listensockaddr;
- socklen_t listensocklen = 0;
- switch (socket_family) {
- case AF_INET:
- listensockaddr = (struct sockaddr *)
- create_inet_sockaddr(cfg_line->value,
- (uint16_t) port_option,
- &address, &listensocklen);
- break;
- case AF_UNIX:
- listensockaddr = (struct sockaddr *)
- create_unix_sockaddr(cfg_line->value,
- &address, &listensocklen);
- break;
- default:
- tor_assert(0);
- }
- if (listensockaddr) {
- conn = connection_create_listener(listensockaddr, listensocklen,
- type, address);
- tor_free(listensockaddr);
- tor_free(address);
- } else
- conn = NULL;
- if (!conn) {
- r = -1;
- } else {
- if (new_conns)
- smartlist_add(new_conns, conn);
- }
- } SMARTLIST_FOREACH_END(cfg_line);
- }
- if (free_launch_elts) {
- SMARTLIST_FOREACH(launch, config_line_t *, cfg_line,
- config_free_lines(cfg_line));
- }
- smartlist_free(launch);
- return r;
- }
- int
- retry_all_listeners(smartlist_t *replaced_conns,
- smartlist_t *new_conns)
- {
- or_options_t *options = get_options();
- if (retry_listeners(CONN_TYPE_OR_LISTENER, options->ORListenAddress,
- options->ORPort, "0.0.0.0",
- replaced_conns, new_conns, options->ClientOnly,
- AF_INET)<0)
- return -1;
- if (retry_listeners(CONN_TYPE_DIR_LISTENER, options->DirListenAddress,
- options->DirPort, "0.0.0.0",
- replaced_conns, new_conns, options->ClientOnly,
- AF_INET)<0)
- return -1;
- if (retry_listeners(CONN_TYPE_AP_LISTENER, options->SocksListenAddress,
- options->SocksPort, "127.0.0.1",
- replaced_conns, new_conns, 0,
- AF_INET)<0)
- return -1;
- if (retry_listeners(CONN_TYPE_AP_TRANS_LISTENER, options->TransListenAddress,
- options->TransPort, "127.0.0.1",
- replaced_conns, new_conns, 0,
- AF_INET)<0)
- return -1;
- if (retry_listeners(CONN_TYPE_AP_NATD_LISTENER, options->NatdListenAddress,
- options->NatdPort, "127.0.0.1",
- replaced_conns, new_conns, 0,
- AF_INET)<0)
- return -1;
- if (retry_listeners(CONN_TYPE_AP_DNS_LISTENER, options->DNSListenAddress,
- options->DNSPort, "127.0.0.1",
- replaced_conns, new_conns, 0,
- AF_INET)<0)
- return -1;
- if (retry_listeners(CONN_TYPE_CONTROL_LISTENER,
- options->ControlListenAddress,
- options->ControlPort, "127.0.0.1",
- replaced_conns, new_conns, 0,
- AF_INET)<0)
- return -1;
- if (retry_listeners(CONN_TYPE_CONTROL_LISTENER,
- options->ControlSocket,
- options->ControlSocket ? 1 : 0, NULL,
- replaced_conns, new_conns, 0,
- AF_UNIX)<0)
- return -1;
- return 0;
- }
- static int
- connection_is_rate_limited(connection_t *conn)
- {
- if (conn->linked ||
- tor_addr_family(&conn->addr) == AF_UNSPEC ||
- tor_addr_is_internal(&conn->addr, 0))
- return 0;
- else
- return 1;
- }
- extern int global_read_bucket, global_write_bucket;
- extern int global_relayed_read_bucket, global_relayed_write_bucket;
- static int write_buckets_empty_last_second = 0;
- #define CLIENT_IDLE_TIME_FOR_PRIORITY 30
- static int
- connection_counts_as_relayed_traffic(connection_t *conn, time_t now)
- {
- if (conn->type == CONN_TYPE_OR &&
- TO_OR_CONN(conn)->client_used + CLIENT_IDLE_TIME_FOR_PRIORITY < now)
- return 1;
- if (conn->type == CONN_TYPE_DIR && DIR_CONN_IS_SERVER(conn))
- return 1;
- return 0;
- }
- static ssize_t
- connection_bucket_round_robin(int base, int priority,
- ssize_t global_bucket, ssize_t conn_bucket)
- {
- ssize_t at_most;
- ssize_t num_bytes_high = (priority ? 32 : 16) * base;
- ssize_t num_bytes_low = (priority ? 4 : 2) * base;
-
- at_most = global_bucket / 8;
- at_most -= (at_most % base);
- if (at_most > num_bytes_high)
- at_most = num_bytes_high;
- else if (at_most < num_bytes_low)
- at_most = num_bytes_low;
- if (at_most > global_bucket)
- at_most = global_bucket;
- if (conn_bucket >= 0 && at_most > conn_bucket)
- at_most = conn_bucket;
- if (at_most < 0)
- return 0;
- return at_most;
- }
- static ssize_t
- connection_bucket_read_limit(connection_t *conn, time_t now)
- {
- int base = connection_speaks_cells(conn) ?
- CELL_NETWORK_SIZE : RELAY_PAYLOAD_SIZE;
- int priority = conn->type != CONN_TYPE_DIR;
- int conn_bucket = -1;
- int global_bucket = global_read_bucket;
- if (connection_speaks_cells(conn)) {
- or_connection_t *or_conn = TO_OR_CONN(conn);
- if (conn->state == OR_CONN_STATE_OPEN)
- conn_bucket = or_conn->read_bucket;
- }
- if (!connection_is_rate_limited(conn)) {
-
- return conn_bucket>=0 ? conn_bucket : 1<<14;
- }
- if (connection_counts_as_relayed_traffic(conn, now) &&
- global_relayed_read_bucket <= global_read_bucket)
- global_bucket = global_relayed_read_bucket;
- return connection_bucket_round_robin(base, priority,
- global_bucket, conn_bucket);
- }
- ssize_t
- connection_bucket_write_limit(connection_t *conn, time_t now)
- {
- int base = connection_speaks_cells(conn) ?
- CELL_NETWORK_SIZE : RELAY_PAYLOAD_SIZE;
- int priority = conn->type != CONN_TYPE_DIR;
- int global_bucket = global_write_bucket;
- if (!connection_is_rate_limited(conn)) {
-
- return conn->outbuf_flushlen;
- }
- if (connection_counts_as_relayed_traffic(conn, now) &&
- global_relayed_write_bucket <= global_write_bucket)
- global_bucket = global_relayed_write_bucket;
- return connection_bucket_round_robin(base, priority, global_bucket,
- conn->outbuf_flushlen);
- }
- int
- global_write_bucket_low(connection_t *conn, size_t attempt, int priority)
- {
- int smaller_bucket = global_write_bucket < global_relayed_write_bucket ?
- global_write_bucket : global_relayed_write_bucket;
- if (authdir_mode(get_options()) && priority>1)
- return 0;
- if (!connection_is_rate_limited(conn))
- return 0;
- if (smaller_bucket < (int)attempt)
- return 1;
- if (write_buckets_empty_last_second)
- return 1;
- if (priority == 1) {
-
- or_options_t *options = get_options();
- int64_t can_write = (int64_t)smaller_bucket
- + 2*(options->RelayBandwidthRate ? options->RelayBandwidthRate :
- options->BandwidthRate);
- if (can_write < 2*(int64_t)attempt)
- return 1;
- } else {
-
- }
- return 0;
- }
- static void
- connection_buckets_decrement(connection_t *conn, time_t now,
- size_t num_read, size_t num_written)
- {
- if (!connection_is_rate_limited(conn))
- return;
- if (num_written >= INT_MAX || num_read >= INT_MAX) {
- log_err(LD_BUG, "Value out of range. num_read=%lu, num_written=%lu, "
- "connection type=%s, state=%s",
- (unsigned long)num_read, (unsigned long)num_written,
- conn_type_to_string(conn->type),
- conn_state_to_string(conn->type, conn->state));
- if (num_written >= INT_MAX) num_written = 1;
- if (num_read >= INT_MAX) num_read = 1;
- tor_fragile_assert();
- }
- if (num_read > 0)
- rep_hist_note_bytes_read(num_read, now);
- if (num_written > 0)
- rep_hist_note_bytes_written(num_written, now);
- if (connection_counts_as_relayed_traffic(conn, now)) {
- global_relayed_read_bucket -= (int)num_read;
- global_relayed_write_bucket -= (int)num_written;
- }
- global_read_bucket -= (int)num_read;
- global_write_bucket -= (int)num_written;
- if (connection_speaks_cells(conn) && conn->state == OR_CONN_STATE_OPEN)
- TO_OR_CONN(conn)->read_bucket -= (int)num_read;
- }
- static void
- connection_consider_empty_read_buckets(connection_t *conn)
- {
- const char *reason;
- if (global_read_bucket <= 0) {
- reason = "global read bucket exhausted. Pausing.";
- } else if (connection_counts_as_relayed_traffic(conn, approx_time()) &&
- global_relayed_read_bucket <= 0) {
- reason = "global relayed read bucket exhausted. Pausing.";
- } else if (connection_speaks_cells(conn) &&
- conn->state == OR_CONN_STATE_OPEN &&
- TO_OR_CONN(conn)->read_bucket <= 0) {
- reason = "connection read bucket exhausted. Pausing.";
- } else
- return;
- LOG_FN_CONN(conn, (LOG_DEBUG, LD_NET, "%s", reason));
- conn->read_blocked_on_bw = 1;
- connection_stop_reading(conn);
- }
- static void
- connection_consider_empty_write_buckets(connection_t *conn)
- {
- const char *reason;
- if (global_write_bucket <= 0) {
- reason = "global write bucket exhausted. Pausing.";
- } else if (connection_counts_as_relayed_traffic(conn, approx_time()) &&
- global_relayed_write_bucket <= 0) {
- reason = "global relayed write bucket exhausted. Pausing.";
- #if 0
- } else if (connection_speaks_cells(conn) &&
- conn->state == OR_CONN_STATE_OPEN &&
- TO_OR_CONN(conn)->write_bucket <= 0) {
- reason = "connection write bucket exhausted. Pausing.";
- #endif
- } else
- return;
- LOG_FN_CONN(conn, (LOG_DEBUG, LD_NET, "%s", reason));
- conn->write_blocked_on_bw = 1;
- connection_stop_writing(conn);
- }
- void
- connection_bucket_init(void)
- {
- or_options_t *options = get_options();
-
- global_read_bucket = (int)options->BandwidthBurst;
- global_write_bucket = (int)options->BandwidthBurst;
- if (options->RelayBandwidthRate) {
- global_relayed_read_bucket = (int)options->RelayBandwidthBurst;
- global_relayed_write_bucket = (int)options->RelayBandwidthBurst;
- } else {
- global_relayed_read_bucket = (int)options->BandwidthBurst;
- global_relayed_write_bucket = (int)options->BandwidthBurst;
- }
- }
- static void
- connection_bucket_refill_helper(int *bucket, int rate, int burst,
- int seconds_elapsed, const char *name)
- {
- int starting_bucket = *bucket;
- if (starting_bucket < burst && seconds_elapsed) {
- if (((burst - starting_bucket)/seconds_elapsed) < rate) {
- *bucket = burst;
- } else {
- int incr = rate*seconds_elapsed;
- *bucket += incr;
- if (*bucket > burst || *bucket < starting_bucket) {
-
-
- *bucket = burst;
- }
- }
- log(LOG_DEBUG, LD_NET,"%s now %d.", name, *bucket);
- }
- }
- void
- connection_bucket_refill(int seconds_elapsed, time_t now)
- {
- or_options_t *options = get_options();
- smartlist_t *conns = get_connection_array();
- int relayrate, relayburst;
- if (options->RelayBandwidthRate) {
- relayrate = (int)options->RelayBandwidthRate;
- relayburst = (int)options->RelayBandwidthBurst;
- } else {
- relayrate = (int)options->BandwidthRate;
- relayburst = (int)options->BandwidthBurst;
- }
- tor_assert(seconds_elapsed >= 0);
- write_buckets_empty_last_second =
- global_relayed_write_bucket <= 0 || global_write_bucket <= 0;
-
- connection_bucket_refill_helper(&global_read_bucket,
- (int)options->BandwidthRate,
- (int)options->BandwidthBurst,
- seconds_elapsed, "global_read_bucket");
- connection_bucket_refill_helper(&global_write_bucket,
- (int)options->BandwidthRate,
- (int)options->BandwidthBurst,
- seconds_elapsed, "global_write_bucket");
- connection_bucket_refill_helper(&global_relayed_read_bucket,
- relayrate, relayburst, seconds_elapsed,
- "global_relayed_read_bucket");
- connection_bucket_refill_helper(&global_relayed_write_bucket,
- relayrate, relayburst, seconds_elapsed,
- "global_relayed_write_bucket");
-
- SMARTLIST_FOREACH(conns, connection_t *, conn,
- {
- if (connection_speaks_cells(conn)) {
- or_connection_t *or_conn = TO_OR_CONN(conn);
- if (connection_read_bucket_should_increase(or_conn)) {
- connection_bucket_refill_helper(&or_conn->read_bucket,
- or_conn->bandwidthrate,
- or_conn->bandwidthburst,
- seconds_elapsed,
- "or_conn->read_bucket");
-
-
- }
- }
- if (conn->read_blocked_on_bw == 1
- && global_read_bucket > 0
- && (!connection_counts_as_relayed_traffic(conn, now) ||
- global_relayed_read_bucket > 0)
- && (!connection_speaks_cells(conn) ||
- conn->state != OR_CONN_STATE_OPEN ||
- TO_OR_CONN(conn)->read_bucket > 0)) {
-
- LOG_FN_CONN(conn, (LOG_DEBUG,LD_NET,
- "waking up conn (fd %d) for read", conn->s));
- conn->read_blocked_on_bw = 0;
- connection_start_reading(conn);
- }
- if (conn->write_blocked_on_bw == 1
- && global_write_bucket > 0
- && (!connection_counts_as_relayed_traffic(conn, now) ||
- global_relayed_write_bucket > 0)) {
-
- LOG_FN_CONN(conn, (LOG_DEBUG,LD_NET,
- "waking up conn (fd %d) for write", conn->s));
- conn->write_blocked_on_bw = 0;
- connection_start_writing(conn);
- }
- });
- }
- static int
- connection_read_bucket_should_increase(or_connection_t *conn)
- {
- tor_assert(conn);
- if (conn->_base.state != OR_CONN_STATE_OPEN)
- return 0;
- if (conn->read_bucket >= conn->bandwidthburst)
- return 0;
- return 1;
- }
- int
- connection_handle_read(connection_t *conn)
- {
- int max_to_read=-1, try_to_read;
- size_t before, n_read = 0;
- int socket_error = 0;
- if (conn->marked_for_close)
- return 0;
- conn->timestamp_lastread = approx_time();
- switch (conn->type) {
- case CONN_TYPE_OR_LISTENER:
- return connection_handle_listener_read(conn, CONN_TYPE_OR);
- case CONN_TYPE_AP_LISTENER:
- case CONN_TYPE_AP_TRANS_LISTENER:
- case CONN_TYPE_AP_NATD_LISTENER:
- return connection_handle_listener_read(conn, CONN_TYPE_AP);
- case CONN_TYPE_DIR_LISTENER:
- return connection_handle_listener_read(conn, CONN_TYPE_DIR);
- case CONN_TYPE_CONTROL_LISTENER:
- return connection_handle_listener_read(conn, CONN_TYPE_CONTROL);
- case CONN_TYPE_AP_DNS_LISTENER:
-
- tor_fragile_assert();
- return 0;
- }
- loop_again:
- try_to_read = max_to_read;
- tor_assert(!conn->marked_for_close);
- before = buf_datalen(conn->inbuf);
- if (connection_read_to_buf(conn, &max_to_read, &socket_error) < 0) {
-
- if (conn->type == CONN_TYPE_OR &&
- conn->state == OR_CONN_STATE_CONNECTING) {
- connection_or_connect_failed(TO_OR_CONN(conn),
- errno_to_orconn_end_reason(socket_error),
- tor_socket_strerror(socket_error));
- }
- if (CONN_IS_EDGE(conn)) {
- edge_connection_t *edge_conn = TO_EDGE_CONN(conn);
- connection_edge_end_errno(edge_conn);
- if (edge_conn->socks_request)
- edge_conn->socks_request->has_finished = 1;
- }
- connection_close_immediate(conn);
- connection_mark_for_close(conn);
- return -1;
- }
- n_read += buf_datalen(conn->inbuf) - before;
- if (CONN_IS_EDGE(conn) && try_to_read != max_to_read) {
-
- if (connection_process_inbuf(conn, 0) < 0) {
- return -1;
- }
- if (!conn->marked_for_close &&
- connection_is_reading(conn) &&
- !conn->inbuf_reached_eof &&
- max_to_read > 0)
- goto loop_again;
- }
-
- if (!conn->marked_for_close &&
- connection_process_inbuf(conn, 1) < 0) {
- return -1;
- }
- if (conn->linked_conn) {
-
- connection_t *linked = conn->linked_conn;
- if (n_read) {
-
- connection_buckets_decrement(linked, approx_time(), 0, n_read);
- if (connection_flushed_some(linked) < 0)
- connection_mark_for_close(linked);
- if (!connection_wants_to_flush(linked))
- connection_finished_flushing(linked);
- }
- if (!buf_datalen(linked->outbuf) && conn->active_on_link)
- connection_stop_reading_from_linked_conn(conn);
- }
-
- if (!conn->marked_for_close &&
- conn->inbuf_reached_eof &&
- connection_reached_eof(conn) < 0) {
- return -1;
- }
- return 0;
- }
- static int
- connection_read_to_buf(connection_t *conn, int *max_to_read, int *socket_error)
- {
- int result;
- ssize_t at_most = *max_to_read;
- size_t slack_in_buf, more_to_read;
- size_t n_read = 0, n_written = 0;
- if (at_most == -1) {
-
- at_most = connection_bucket_read_limit(conn, approx_time());
- }
- slack_in_buf = buf_slack(conn->inbuf);
- again:
- if ((size_t)at_most > slack_in_buf && slack_in_buf >= 1024) {
- more_to_read = at_most - slack_in_buf;
- at_most = slack_in_buf;
- } else {
- more_to_read = 0;
- }
- if (connection_speaks_cells(conn) &&
- conn->state > OR_CONN_STATE_PROXY_HANDSHAKING) {
- int pending;
- or_connection_t *or_conn = TO_OR_CONN(conn);
- size_t initial_size;
- if (conn->state == OR_CONN_STATE_TLS_HANDSHAKING ||
- conn->state == OR_CONN_STATE_TLS_CLIENT_RENEGOTIATING) {
-
- return connection_tls_continue_handshake(or_conn);
- }
- log_debug(LD_NET,
- "%d: starting, inbuf_datalen %ld (%d pending in tls object)."
- " at_most %ld.",
- conn->s,(long)buf_datalen(conn->inbuf),
- tor_tls_get_pending_bytes(or_conn->tls), (long)at_most);
- initial_size = buf_datalen(conn->inbuf);
-
- result = read_to_buf_tls(or_conn->tls, at_most, conn->inbuf);
- if (TOR_TLS_IS_ERROR(result) || result == TOR_TLS_CLOSE)
- or_conn->tls_error = result;
- else
- or_conn->tls_error = 0;
- switch (result) {
- case TOR_TLS_CLOSE:
- case TOR_TLS_ERROR_IO:
- log_debug(LD_NET,"TLS connection closed %son read. Closing. "
- "(Nickname %s, address %s)",
- result == TOR_TLS_CLOSE ? "cleanly " : "",
- or_conn->nickname ? or_conn->nickname : "not set",
- conn->address);
- return result;
- CASE_TOR_TLS_ERROR_ANY_NONIO:
- log_debug(LD_NET,"tls error [%s]. breaking (nickname %s, address %s).",
- tor_tls_err_to_string(result),
- or_conn->nickname ? or_conn->nickname : "not set",
- conn->address);
- return result;
- case TOR_TLS_WANTWRITE:
- connection_start_writing(conn);
- return 0;
- case TOR_TLS_WANTREAD:
- case TOR_TLS_DONE:
- result = 0;
- break;
- default:
- break;
- }
- pending = tor_tls_get_pending_bytes(or_conn->tls);
- if (pending) {
-
- int r2 = read_to_buf_tls(or_conn->tls, pending, conn->inbuf);
- if (r2<0) {
- log_warn(LD_BUG, "apparently, reading pending bytes can fail.");
- return -1;
- }
- }
- result = (int)(buf_datalen(conn->inbuf)-initial_size);
- tor_tls_get_n_raw_bytes(or_conn->tls, &n_read, &n_written);
- log_debug(LD_GENERAL, "After TLS read of %d: %ld read, %ld written",
- result, (long)n_read, (long)n_written);
- } else if (conn->linked) {
- if (conn->linked_conn) {
- result = move_buf_to_buf(conn->inbuf, conn->linked_conn->outbuf,
- &conn->linked_conn->outbuf_flushlen);
- } else {
- result = 0;
- }
-
-
- if (!conn->linked_conn ||
- (conn->linked_conn->marked_for_close &&
- buf_datalen(conn->linked_conn->outbuf) == 0))
- conn->inbuf_reached_eof = 1;
- n_read = (size_t) result;
- } else {
-
- int reached_eof = 0;
- CONN_LOG_PROTECT(conn,
- result = read_to_buf(conn->s, at_most, conn->inbuf, &reached_eof,
- socket_error));
- if (reached_eof)
- conn->inbuf_reached_eof = 1;
- if (result < 0)
- return -1;
- n_read = (size_t) result;
- }
- if (n_read > 0) {
-
- *max_to_read = (int)(at_most - n_read);
- }
- if (conn->type == CONN_TYPE_AP) {
- edge_connection_t *edge_conn = TO_EDGE_CONN(conn);
-
- edge_conn->n_read += (int)n_read;
- }
- connection_buckets_decrement(conn, approx_time(), n_read, n_written);
- if (more_to_read && result == at_most) {
- slack_in_buf = buf_slack(conn->inbuf);
- at_most = more_to_read;
- goto again;
- }
-
- connection_consider_empty_read_buckets(conn);
- if (n_written > 0 && connection_is_writing(conn))
- connection_consider_empty_write_buckets(conn);
- return 0;
- }
- int
- connection_fetch_from_buf(char *string, size_t len, connection_t *conn)
- {
- return fetch_from_buf(string, len, conn->inbuf);
- }
- int
- connection_wants_to_flush(connection_t *conn)
- {
- return conn->outbuf_flushlen > 0;
- }
- int
- connection_outbuf_too_full(connection_t *conn)
- {
- return (conn->outbuf_flushlen > 10*CELL_PAYLOAD_SIZE);
- }
- int
- connection_handle_write(connection_t *conn, int force)
- {
- int e;
- socklen_t len=(socklen_t)sizeof(e);
- int result;
- ssize_t max_to_write;
- time_t now = approx_time();
- size_t n_read = 0, n_written = 0;
- tor_assert(!connection_is_listener(conn));
- if (conn->marked_for_close || conn->s < 0)
- return 0;
- if (conn->in_flushed_some) {
- log_warn(LD_BUG, "called recursively from inside conn->in_flushed_some()");
- return 0;
- }
- conn->timestamp_lastwritten = now;
-
- if (connection_state_is_connecting(conn)) {
- if (getsockopt(conn->s, SOL_SOCKET, SO_ERROR, (void*)&e, &len) < 0) {
- log_warn(LD_BUG,
- "getsockopt() syscall failed?! Please report to tor-ops.");
- if (CONN_IS_EDGE(conn))
- connection_edge_end_errno(TO_EDGE_CONN(conn));
- connection_mark_for_close(conn);
- return -1;
- }
- if (e) {
-
- if (!ERRNO_IS_CONN_EINPROGRESS(e)) {
- log_info(LD_NET,"in-progress connect failed. Removing. (%s)",
- tor_socket_strerror(e));
- if (CONN_IS_EDGE(conn))
- connection_edge_end_errno(TO_EDGE_CONN(conn));
- if (conn->type == CONN_TYPE_OR)
- connection_or_connect_failed(TO_OR_CONN(conn),
- errno_to_orconn_end_reason(e),
- tor_socket_strerror(e));
- connection_close_immediate(conn);
- connection_mark_for_close(conn);
- return -1;
- } else {
- return 0;
- }
- }
-
- if (connection_finished_connecting(conn)<0)
- return -1;
- }
- max_to_write = force ? (ssize_t)conn->outbuf_flushlen
- : connection_bucket_write_limit(conn, now);
- if (connection_speaks_cells(conn) &&
- conn->state > OR_CONN_STATE_PROXY_HANDSHAKING) {
- or_connection_t *or_conn = TO_OR_CONN(conn);
- if (conn->state == OR_CONN_STATE_TLS_HANDSHAKING ||
- conn->state == OR_CONN_STATE_TLS_CLIENT_RENEGOTIATING) {
- connection_stop_writing(conn);
- if (connection_tls_continue_handshake(or_conn) < 0) {
-
- connection_close_immediate(conn);
- connection_mark_for_close(conn);
- return -1;
- }
- return 0;
- } else if (conn->state == OR_CONN_STATE_TLS_SERVER_RENEGOTIATING) {
- return connection_handle_read(conn);
- }
-
- result = flush_buf_tls(or_conn->tls, conn->outbuf,
- max_to_write, &conn->outbuf_flushlen);
- switch (result) {
- CASE_TOR_TLS_ERROR_ANY:
- case TOR_TLS_CLOSE:
- log_info(LD_NET,result!=TOR_TLS_CLOSE?
- "tls error. breaking.":"TLS connection closed on flush");
-
- connection_close_immediate(conn);
- connection_mark_for_close(conn);
- return -1;
- case TOR_TLS_WANTWRITE:
- log_debug(LD_NET,"wanted write.");
-
- return 0;
- case TOR_TLS_WANTREAD:
-
- log_debug(LD_NET,"wanted read.");
- if (!connection_is_reading(conn)) {
- connection_stop_writing(conn);
- conn->write_blocked_on_bw = 1;
-
- }
-
- return 0;
-
- }
- tor_tls_get_n_raw_bytes(or_conn->tls, &n_read, &n_written);
- log_debug(LD_GENERAL, "After TLS write of %d: %ld read, %ld written",
- result, (long)n_read, (long)n_written);
- } else {
- CONN_LOG_PROTECT(conn,
- result = flush_buf(conn->s, conn->outbuf,
- max_to_write, &conn->outbuf_flushlen));
- if (result < 0) {
- if (CONN_IS_EDGE(conn))
- connection_edge_end_errno(TO_EDGE_CONN(conn));
- connection_close_immediate(conn);
- connection_mark_for_close(conn);
- return -1;
- }
- n_written = (size_t) result;
- }
- if (conn->type == CONN_TYPE_AP) {
- edge_connection_t *edge_conn = TO_EDGE_CONN(conn);
-
- edge_conn->n_written += (int)n_written;
- }
- connection_buckets_decrement(conn, approx_time(), n_read, n_written);
- if (result > 0) {
-
- if (connection_flushed_some(conn) < 0)
- connection_mark_for_close(conn);
- }
- if (!connection_wants_to_flush(conn)) {
- if (connection_finished_flushing(conn) < 0) {
-
- return -1;
- }
- return 0;
- }
-
- connection_consider_empty_write_buckets(conn);
- if (n_read > 0 && connection_is_reading(conn))
- connection_consider_empty_read_buckets(conn);
- return 0;
- }
- #define MIN_TLS_FLUSHLEN 15872
- void
- _connection_write_to_buf_impl(const char *string, size_t len,
- connection_t *conn, int zlib)
- {
-
- int r;
- size_t old_datalen;
- if (!len && !(zlib<0))
- return;
-
- if (conn->marked_for_close && !conn->hold_open_until_flushed)
- return;
- old_datalen = buf_datalen(conn->outbuf);
- if (zlib) {
- dir_connection_t *dir_conn = TO_DIR_CONN(conn);
- int done = zlib < 0;
- CONN_LOG_PROTECT(conn, r = write_to_buf_zlib(conn->outbuf,
- dir_conn->zlib_state,
- string, len, done));
- } else {
- CONN_LOG_PROTECT(conn, r = write_to_buf(string, len, conn->outbuf));
- }
- if (r < 0) {
- if (CONN_IS_EDGE(conn)) {
-
- log_warn(LD_NET,
- "write_to_buf failed. Closing circuit (fd %d).", conn->s);
- circuit_mark_for_close(circuit_get_by_edge_conn(TO_EDGE_CONN(conn)),
- END_CIRC_REASON_INTERNAL);
- } else {
- log_warn(LD_NET,
- "write_to_buf failed. Closing connection (fd %d).", conn->s);
- connection_mark_for_close(conn);
- }
- return;
- }
- connection_start_writing(conn);
- if (zlib) {
- conn->outbuf_flushlen += buf_datalen(conn->outbuf) - old_datalen;
- } else {
- ssize_t extra = 0;
- conn->outbuf_flushlen += len;
-
- if (conn->in_flushed_some) {
-
- return;
- }
- if (conn->type == CONN_TYPE_OR &&
- conn->outbuf_flushlen-len < MIN_TLS_FLUSHLEN &&
- conn->outbuf_flushlen >= MIN_TLS_FLUSHLEN) {
-
- extra = conn->outbuf_flushlen - MIN_TLS_FLUSHLEN;
- conn->outbuf_flushlen = MIN_TLS_FLUSHLEN;
- } else if (conn->type == CONN_TYPE_CONTROL &&
- !connection_is_rate_limited(conn) &&
- conn->outbuf_flushlen-len < 1<<16 &&
- conn->outbuf_flushlen >= 1<<16) {
-
- } else
- return;
- if (connection_handle_write(conn, 0) < 0) {
- if (!conn->marked_for_close) {
-
- log_warn(LD_BUG, "unhandled error on write for "
- "conn (type %d, fd %d); removing",
- conn->type, conn->s);
- tor_fragile_assert();
-
- connection_close_immediate(conn);
- }
- return;
- }
- if (extra) {
- conn->outbuf_flushlen += extra;
- connection_start_writing(conn);
- }
- }
- }
- connection_t *
- connection_get_by_type_addr_port_purpose(int type,
- const tor_addr_t *addr, uint16_t port,
- int purpose)
- {
- smartlist_t *conns = get_connection_array();
- SMARTLIST_FOREACH(conns, connection_t *, conn,
- {
- if (conn->type == type &&
- tor_addr_eq(&conn->addr, addr) &&
- conn->port == port &&
- conn->purpose == purpose &&
- !conn->marked_for_close)
- return conn;
- });
- return NULL;
- }
- connection_t *
- connection_get_by_global_id(uint64_t id)
- {
- smartlist_t *conns = get_connection_array();
- SMARTLIST_FOREACH(conns, connection_t *, conn,
- {
- if (conn->global_identifier == id)
- return conn;
- });
- return NULL;
- }
- connection_t *
- connection_get_by_type(int type)
- {
- smartlist_t *conns = get_connection_array();
- SMARTLIST_FOREACH(conns, connection_t *, conn,
- {
- if (conn->type == type && !conn->marked_for_close)
- return conn;
- });
- return NULL;
- }
- connection_t *
- connection_get_by_type_state(int type, int state)
- {
- smartlist_t *conns = get_connection_array();
- SMARTLIST_FOREACH(conns, connection_t *, conn,
- {
- if (conn->type == type && conn->state == state && !conn->marked_for_close)
- return conn;
- });
- return NULL;
- }
- connection_t *
- connection_get_by_type_state_rendquery(int type, int state,
- const char *rendquery)
- {
- smartlist_t *conns = get_connection_array();
- tor_assert(type == CONN_TYPE_DIR ||
- type == CONN_TYPE_AP || type == CONN_TYPE_EXIT);
- tor_assert(rendquery);
- SMARTLIST_FOREACH(conns, connection_t *, conn,
- {
- if (conn->type == type &&
- !conn->marked_for_close &&
- (!state || state == conn->state)) {
- if (type == CONN_TYPE_DIR &&
- TO_DIR_CONN(conn)->rend_data &&
- !rend_cmp_service_ids(rendquery,
- TO_DIR_CONN(conn)->rend_data->onion_address))
- return conn;
- else if (CONN_IS_EDGE(conn) &&
- TO_EDGE_CONN(conn)->rend_data &&
- !rend_cmp_service_ids(rendquery,
- TO_EDGE_CONN(conn)->rend_data->onion_address))
- return conn;
- }
- });
- return NULL;
- }
- connection_t *
- connection_get_by_type_purpose(int type, int purpose)
- {
- smartlist_t *conns = get_connection_array();
- SMARTLIST_FOREACH(conns, connection_t *, conn,
- {
- if (conn->type == type &&
- !conn->marked_for_close &&
- (purpose == conn->purpose))
- return conn;
- });
- return NULL;
- }
- int
- connection_is_listener(connection_t *conn)
- {
- if (conn->type == CONN_TYPE_OR_LISTENER ||
- conn->type == CONN_TYPE_AP_LISTENER ||
- conn->type == CONN_TYPE_AP_TRANS_LISTENER ||
- conn->type == CONN_TYPE_AP_DNS_LISTENER ||
- conn->type == CONN_TYPE_AP_NATD_LISTENER ||
- conn->type == CONN_TYPE_DIR_LISTENER ||
- conn->type == CONN_TYPE_CONTROL_LISTENER)
- return 1;
- return 0;
- }
- int
- connection_state_is_open(connection_t *conn)
- {
- tor_assert(conn);
- if (conn->marked_for_close)
- return 0;
- if ((conn->type == CONN_TYPE_OR && conn->state == OR_CONN_STATE_OPEN) ||
- (conn->type == CONN_TYPE_AP && conn->state == AP_CONN_STATE_OPEN) ||
- (conn->type == CONN_TYPE_EXIT && conn->state == EXIT_CONN_STATE_OPEN) ||
- (conn->type == CONN_TYPE_CONTROL &&
- conn->state == CONTROL_CONN_STATE_OPEN))
- return 1;
- return 0;
- }
- int
- connection_state_is_connecting(connection_t *conn)
- {
- tor_assert(conn);
- if (conn->marked_for_close)
- return 0;
- switch (conn->type)
- {
- case CONN_TYPE_OR:
- return conn->state == OR_CONN_STATE_CONNECTING;
- case CONN_TYPE_EXIT:
- return conn->state == EXIT_CONN_STATE_CONNECTING;
- case CONN_TYPE_DIR:
- return conn->state == DIR_CONN_STATE_CONNECTING;
- }
- return 0;
- }
- char *
- alloc_http_authenticator(const char *authenticator)
- {
-
- const size_t authenticator_length = strlen(authenticator);
-
- const size_t base64_authenticator_length = (authenticator_length/48+1)*66;
- char *base64_authenticator = tor_malloc(base64_authenticator_length);
- if (base64_encode(base64_authenticator, base64_authenticator_length,
- authenticator, authenticator_length) < 0) {
- tor_free(base64_authenticator);
- } else {
-
- base64_authenticator[strlen(base64_authenticator) - 1] = 0;
- }
- return base64_authenticator;
- }
- static void
- client_check_address_changed(int sock)
- {
- uint32_t iface_ip, ip_out;
- struct sockaddr_in out_addr;
- socklen_t out_addr_len = (socklen_t) sizeof(out_addr);
- uint32_t *ip;
- if (!last_interface_ip)
- get_interface_address(LOG_INFO, &last_interface_ip);
- if (!outgoing_addrs)
- outgoing_addrs = smartlist_create();
- if (getsockname(sock, (struct sockaddr*)&out_addr, &out_addr_len)<0) {
- int e = tor_socket_errno(sock);
- log_warn(LD_NET, "getsockname() to check for address change failed: %s",
- tor_socket_strerror(e));
- return;
- }
-
- ip_out = ntohl(out_addr.sin_addr.s_addr);
- SMARTLIST_FOREACH(outgoing_addrs, uint32_t*, ip_ptr,
- if (*ip_ptr == ip_out) return;
- );
-
- if (get_interface_address(LOG_INFO, &iface_ip)<0)
- return;
- ip = tor_malloc(sizeof(uint32_t));
- *ip = ip_out;
- if (iface_ip == last_interface_ip) {
-
- smartlist_add(outgoing_addrs, ip);
- } else {
-
- log(LOG_NOTICE, LD_NET, "Our IP address has changed. Rotating keys...");
- last_interface_ip = iface_ip;
- SMARTLIST_FOREACH(outgoing_addrs, void*, ip_ptr, tor_free(ip_ptr));
- smartlist_clear(outgoing_addrs);
- smartlist_add(outgoing_addrs, ip);
-
- ip_address_changed(1);
- }
- }
- static void
- set_constrained_socket_buffers(int sock, int size)
- {
- void *sz = (void*)&size;
- socklen_t sz_sz = (socklen_t) sizeof(size);
- if (setsockopt(sock, SOL_SOCKET, SO_SNDBUF, sz, sz_sz) < 0) {
- int e = tor_socket_errno(sock);
- log_warn(LD_NET, "setsockopt() to constrain send "
- "buffer to %d bytes failed: %s", size, tor_socket_strerror(e));
- }
- if (setsockopt(sock, SOL_SOCKET, SO_RCVBUF, sz, sz_sz) < 0) {
- int e = tor_socket_errno(sock);
- log_warn(LD_NET, "setsockopt() to constrain recv "
- "buffer to %d bytes failed: %s", size, tor_socket_strerror(e));
- }
- }
- static int
- connection_process_inbuf(connection_t *conn, int package_partial)
- {
- tor_assert(conn);
- switch (conn->type) {
- case CONN_TYPE_OR:
- return connection_or_process_inbuf(TO_OR_CONN(conn));
- case CONN_TYPE_EXIT:
- case CONN_TYPE_AP:
- return connection_edge_process_inbuf(TO_EDGE_CONN(conn),
- package_partial);
- case CONN_TYPE_DIR:
- return connection_dir_process_inbuf(TO_DIR_CONN(conn));
- case CONN_TYPE_CPUWORKER:
- return connection_cpu_process_inbuf(conn);
- case CONN_TYPE_CONTROL:
- return connection_control_process_inbuf(TO_CONTROL_CONN(conn));
- default:
- log_err(LD_BUG,"got unexpected conn type %d.", conn->type);
- tor_fragile_assert();
- return -1;
- }
- }
- static int
- connection_flushed_some(connection_t *conn)
- {
- int r = 0;
- tor_assert(!conn->in_flushed_some);
- conn->in_flushed_some = 1;
- if (conn->type == CONN_TYPE_DIR &&
- conn->state == DIR_CONN_STATE_SERVER_WRITING) {
- r = connection_dirserv_flushed_some(TO_DIR_CONN(conn));
- } else if (conn->type == CONN_TYPE_OR) {
- r = connection_or_flushed_some(TO_OR_CONN(conn));
- }
- conn->in_flushed_some = 0;
- return r;
- }
- static int
- connection_finished_flushing(connection_t *conn)
- {
- tor_assert(conn);
-
- if (CONN_IS_CLOSED(conn))
- return 0;
- switch (conn->type) {
- case CONN_TYPE_OR:
- return connection_or_finished_flushing(TO_OR_CONN(conn));
- case CONN_TYPE_AP:
- case CONN_TYPE_EXIT:
- return connection_edge_finished_flushing(TO_EDGE_CONN(conn));
- case CONN_TYPE_DIR:
- return connection_dir_finished_flushing(TO_DIR_CONN(conn));
- case CONN_TYPE_CPUWORKER:
- return connection_cpu_finished_flushing(conn);
- case CONN_TYPE_CONTROL:
- return connection_control_finished_flushing(TO_CONTROL_CONN(conn));
- default:
- log_err(LD_BUG,"got unexpected conn type %d.", conn->type);
- tor_fragile_assert();
- return -1;
- }
- }
- static int
- connection_finished_connecting(connection_t *conn)
- {
- tor_assert(conn);
- switch (conn->type)
- {
- case CONN_TYPE_OR:
- return connection_or_finished_connecting(TO_OR_CONN(conn));
- case CONN_TYPE_EXIT:
- return connection_edge_finished_connecting(TO_EDGE_CONN(conn));
- case CONN_TYPE_DIR:
- return connection_dir_finished_connecting(TO_DIR_CONN(conn));
- default:
- log_err(LD_BUG,"got unexpected conn type %d.", conn->type);
- tor_fragile_assert();
- return -1;
- }
- }
- static int
- connection_reached_eof(connection_t *conn)
- {
- switch (conn->type) {
- case CONN_TYPE_OR:
- return connection_or_reached_eof(TO_OR_CONN(conn));
- case CONN_TYPE_AP:
- case CONN_TYPE_EXIT:
- return connection_edge_reached_eof(TO_EDGE_CONN(conn));
- case CONN_TYPE_DIR:
- return connection_dir_reached_eof(TO_DIR_CONN(conn));
- case CONN_TYPE_CPUWORKER:
- return connection_cpu_reached_eof(conn);
- case CONN_TYPE_CONTROL:
- return connection_control_reached_eof(TO_CONTROL_CONN(conn));
- default:
- log_err(LD_BUG,"got unexpected conn type %d.", conn->type);
- tor_fragile_assert();
- return -1;
- }
- }
- void
- connection_dump_buffer_mem_stats(int severity)
- {
- uint64_t used_by_type[_CONN_TYPE_MAX+1];
- uint64_t alloc_by_type[_CONN_TYPE_MAX+1];
- int n_conns_by_type[_CONN_TYPE_MAX+1];
- uint64_t total_alloc = 0;
- uint64_t total_used = 0;
- int i;
- smartlist_t *conns = get_connection_array();
- memset(used_by_type, 0, sizeof(used_by_type));
- memset(alloc_by_type, 0, sizeof(alloc_by_type));
- memset(n_conns_by_type, 0, sizeof(n_conns_by_type));
- SMARTLIST_FOREACH(conns, connection_t *, c,
- {
- int tp = c->type;
- ++n_conns_by_type[tp];
- if (c->inbuf) {
- used_by_type[tp] += buf_datalen(c->inbuf);
- alloc_by_type[tp] += buf_allocation(c->inbuf);
- }
- if (c->outbuf) {
- used_by_type[tp] += buf_datalen(c->outbuf);
- alloc_by_type[tp] += buf_allocation(c->outbuf);
- }
- });
- for (i=0; i <= _CONN_TYPE_MAX; ++i) {
- total_used += used_by_type[i];
- total_alloc += alloc_by_type[i];
- }
- log(severity, LD_GENERAL,
- "In buffers for %d connections: "U64_FORMAT" used/"U64_FORMAT" allocated",
- smartlist_len(conns),
- U64_PRINTF_ARG(total_used), U64_PRINTF_ARG(total_alloc));
- for (i=_CONN_TYPE_MIN; i <= _CONN_TYPE_MAX; ++i) {
- if (!n_conns_by_type[i])
- continue;
- log(severity, LD_GENERAL,
- " For %d %s connections: "U64_FORMAT" used/"U64_FORMAT" allocated",
- n_conns_by_type[i], conn_type_to_string(i),
- U64_PRINTF_ARG(used_by_type[i]), U64_PRINTF_ARG(alloc_by_type[i]));
- }
- }
- void
- assert_connection_ok(connection_t *conn, time_t now)
- {
- (void) now;
- tor_assert(conn);
- tor_assert(conn->type >= _CONN_TYPE_MIN);
- tor_assert(conn->type <= _CONN_TYPE_MAX);
- switch (conn->type) {
- case CONN_TYPE_OR:
- tor_assert(conn->magic == OR_CONNECTION_MAGIC);
- break;
- case CONN_TYPE_AP:
- case CONN_TYPE_EXIT:
- tor_assert(conn->magic == EDGE_CONNECTION_MAGIC);
- break;
- case CONN_TYPE_DIR:
- tor_assert(conn->magic == DIR_CONNECTION_MAGIC);
- break;
- case CONN_TYPE_CONTROL:
- tor_assert(conn->magic == CONTROL_CONNECTION_MAGIC);
- break;
- default:
- tor_assert(conn->magic == BASE_CONNECTION_MAGIC);
- break;
- }
- if (conn->linked_conn) {
- tor_assert(conn->linked_conn->linked_conn == conn);
- tor_assert(conn->linked);
- }
- if (conn->linked)
- tor_assert(conn->s < 0);
- if (conn->outbuf_flushlen > 0) {
- tor_assert(connection_is_writing(conn) || conn->write_blocked_on_bw ||
- (CONN_IS_EDGE(conn) && TO_EDGE_CONN(conn)->edge_blocked_on_circ));
- }
- if (conn->hold_open_until_flushed)
- tor_assert(conn->marked_for_close);
-
-
- if (!connection_is_listener(conn)) {
- assert_buf_ok(conn->inbuf);
- assert_buf_ok(conn->outbuf);
- }
- if (conn->type == CONN_TYPE_OR) {
- or_connection_t *or_conn = TO_OR_CONN(conn);
- if (conn->state == OR_CONN_STATE_OPEN) {
-
-
- }
- tor_assert(conn->address);
- if (conn->state > OR_CONN_STATE_PROXY_HANDSHAKING)
- tor_assert(or_conn->tls);
- }
- if (CONN_IS_EDGE(conn)) {
- edge_connection_t *edge_conn = TO_EDGE_CONN(conn);
- if (edge_conn->chosen_exit_optional || edge_conn->chosen_exit_retries) {
- tor_assert(conn->type == CONN_TYPE_AP);
- tor_assert(edge_conn->chosen_exit_name);
- }
-
- if (conn->type == CONN_TYPE_AP) {
- tor_assert(edge_conn->socks_request);
- if (conn->state == AP_CONN_STATE_OPEN) {
- tor_assert(edge_conn->socks_request->has_finished);
- if (!conn->marked_for_close) {
- tor_assert(edge_conn->cpath_layer);
- assert_cpath_layer_ok(edge_conn->cpath_layer);
- }
- }
- }
- if (conn->type == CONN_TYPE_EXIT) {
- tor_assert(conn->purpose == EXIT_PURPOSE_CONNECT ||
- conn->purpose == EXIT_PURPOSE_RESOLVE);
- }
- } else if (conn->type == CONN_TYPE_DIR) {
- } else {
-
- tor_assert(!conn->purpose);
- }
- switch (conn->type)
- {
- case CONN_TYPE_OR_LISTENER:
- case CONN_TYPE_AP_LISTENER:
- case CONN_TYPE_AP_TRANS_LISTENER:
- case CONN_TYPE_AP_NATD_LISTENER:
- case CONN_TYPE_DIR_LISTENER:
- case CONN_TYPE_CONTROL_LISTENER:
- case CONN_TYPE_AP_DNS_LISTENER:
- tor_assert(conn->state == LISTENER_STATE_READY);
- break;
- case CONN_TYPE_OR:
- tor_assert(conn->state >= _OR_CONN_STATE_MIN);
- tor_assert(conn->state <= _OR_CONN_STATE_MAX);
- tor_assert(TO_OR_CONN(conn)->n_circuits >= 0);
- break;
- case CONN_TYPE_EXIT:
- tor_assert(conn->state >= _EXIT_CONN_STATE_MIN);
- tor_assert(conn->state <= _EXIT_CONN_STATE_MAX);
- tor_assert(conn->purpose >= _EXIT_PURPOSE_MIN);
- tor_assert(conn->purpose <= _EXIT_PURPOSE_MAX);
- break;
- case CONN_TYPE_AP:
- tor_assert(conn->state >= _AP_CONN_STATE_MIN);
- tor_assert(conn->state <= _AP_CONN_STATE_MAX);
- tor_assert(TO_EDGE_CONN(conn)->socks_request);
- break;
- case CONN_TYPE_DIR:
- tor_assert(conn->state >= _DIR_CONN_STATE_MIN);
- tor_assert(conn->state <= _DIR_CONN_STATE_MAX);
- tor_assert(conn->purpose >= _DIR_PURPOSE_MIN);
- tor_assert(conn->purpose <= _DIR_PURPOSE_MAX);
- break;
- case CONN_TYPE_CPUWORKER:
- tor_assert(conn->state >= _CPUWORKER_STATE_MIN);
- tor_assert(conn->state <= _CPUWORKER_STATE_MAX);
- break;
- case CONN_TYPE_CONTROL:
- tor_assert(conn->state >= _CONTROL_CONN_STATE_MIN);
- tor_assert(conn->state <= _CONTROL_CONN_STATE_MAX);
- break;
- default:
- tor_assert(0);
- }
- }
|