/* * CCC function for the HTTP module */ void a_Http_ccc(int Op, int Branch, int Dir, ChainLink *Info, void *Data1, void *Data2) { int SKey = VOIDP2INT(Info->LocalKey); (void)Data2; /* suppress unused parameter warning */ dReturn_if_fail( a_Chain_check("a_Http_ccc", Op, Branch, Dir, Info) ); if (Branch == 1) { if (Dir == BCK) { /* HTTP query branch */ switch (Op) { case OpStart: /* ( Data1 = Web ) */ SKey = Http_sock_new(); Info->LocalKey = INT2VOIDP(SKey); /* link IO */ a_Chain_link_new(Info, a_Http_ccc, BCK, a_IO_ccc, 1, 1); a_Chain_bcb(OpStart, Info, NULL, NULL); /* async. connection */ Http_get(Info, Data1); break; case OpEnd: /* finished the HTTP query branch */ a_Chain_bcb(OpEnd, Info, NULL, NULL); Http_socket_free(SKey); dFree(Info); break; case OpAbort: /* something bad happened... */ a_Chain_bcb(OpAbort, Info, NULL, NULL); Http_socket_free(SKey); dFree(Info); break; } } else { /* 1 FWD */ /* HTTP send-query status branch */ switch (Op) { default: MSG_WARN("Unused CCC\n"); break; } } } }
/* * Create and submit the HTTP query to the IO engine */ static void Http_send_query(ChainLink *Info, SocketData_t *S) { Dstr *query; DataBuf *dbuf; /* Create the query */ query = a_Http_make_query_str(S->web->url, S->web->requester, S->flags & HTTP_SOCKET_USE_PROXY); dbuf = a_Chain_dbuf_new(query->str, query->len, 0); /* actually this message is sent too early. * It should go when the socket is ready for writing (i.e. connected) */ _MSG_BW(S->web, 1, "Sending query to %s...", URL_HOST_(S->web->url)); /* send query */ a_Chain_bcb(OpSend, Info, dbuf, NULL); dFree(dbuf); dStr_free(query, 1); }
/* * This function gets called after the DNS succeeds solving a hostname. * Task: Finish socket setup and start connecting the socket. * Return value: 0 on success; -1 on error. */ static int Http_connect_socket(ChainLink *Info) { int i, status; #ifdef ENABLE_IPV6 struct sockaddr_in6 name; #else struct sockaddr_in name; #endif SocketData_t *S; DilloHost *dh; socklen_t socket_len = 0; S = a_Klist_get_data(ValidSocks, VOIDP2INT(Info->LocalKey)); /* TODO: iterate this address list until success, or end-of-list */ for (i = 0; (dh = dList_nth_data(S->addr_list, i)); ++i) { if ((S->SockFD = socket(dh->af, SOCK_STREAM, IPPROTO_TCP)) < 0) { S->Err = errno; MSG("Http_connect_socket ERROR: %s\n", dStrerror(errno)); continue; } /* set NONBLOCKING and close on exec. */ fcntl(S->SockFD, F_SETFL, O_NONBLOCK | fcntl(S->SockFD, F_GETFL)); fcntl(S->SockFD, F_SETFD, FD_CLOEXEC | fcntl(S->SockFD, F_GETFD)); /* Some OSes require this... */ memset(&name, 0, sizeof(name)); /* Set remaining parms. */ switch (dh->af) { case AF_INET: { struct sockaddr_in *sin = (struct sockaddr_in *)&name; socket_len = sizeof(struct sockaddr_in); sin->sin_family = dh->af; sin->sin_port = S->port ? htons(S->port) : htons(DILLO_URL_HTTP_PORT); memcpy(&sin->sin_addr, dh->data, (size_t)dh->alen); if (a_Web_valid(S->web) && (S->web->flags & WEB_RootUrl)) MSG("Connecting to %s\n", inet_ntoa(sin->sin_addr)); break; } #ifdef ENABLE_IPV6 case AF_INET6: { char buf[128]; struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)&name; socket_len = sizeof(struct sockaddr_in6); sin6->sin6_family = dh->af; sin6->sin6_port = S->port ? htons(S->port) : htons(DILLO_URL_HTTP_PORT); memcpy(&sin6->sin6_addr, dh->data, dh->alen); inet_ntop(dh->af, dh->data, buf, sizeof(buf)); if (a_Web_valid(S->web) && (S->web->flags & WEB_RootUrl)) MSG("Connecting to %s\n", buf); break; } #endif }/*switch*/ MSG_BW(S->web, 1, "Contacting host..."); status = connect(S->SockFD, (struct sockaddr *)&name, socket_len); if (status == -1 && errno != EINPROGRESS) { S->Err = errno; Http_socket_close(S); MSG("Http_connect_socket ERROR: %s\n", dStrerror(S->Err)); } else { a_Chain_bcb(OpSend, Info, &S->SockFD, "FD"); a_Chain_fcb(OpSend, Info, &S->SockFD, "FD"); Http_send_query(S->Info, S); return 0; /* Success */ } } return -1; }
/* * CCC function for the CAPI module */ void a_Capi_ccc(int Op, int Branch, int Dir, ChainLink *Info, void *Data1, void *Data2) { capi_conn_t *conn; dReturn_if_fail( a_Chain_check("a_Capi_ccc", Op, Branch, Dir, Info) ); if (Branch == 1) { if (Dir == BCK) { /* Command sending branch */ switch (Op) { case OpStart: /* Data1 = conn; Data2 = {Web | server} */ conn = Data1; Capi_conn_ref(conn); Info->LocalKey = conn; conn->InfoSend = Info; if (strcmp(conn->server, "http") == 0) { a_Chain_link_new(Info, a_Capi_ccc, BCK, a_Http_ccc, 1, 1); a_Chain_bcb(OpStart, Info, Data2, NULL); } else { a_Chain_link_new(Info, a_Capi_ccc, BCK, a_Dpi_ccc, 1, 1); a_Chain_bcb(OpStart, Info, Data2, NULL); } break; case OpSend: /* Data1 = dbuf */ a_Chain_bcb(OpSend, Info, Data1, NULL); break; case OpEnd: conn = Info->LocalKey; conn->InfoSend = NULL; a_Chain_bcb(OpEnd, Info, NULL, NULL); Capi_conn_unref(conn); dFree(Info); break; case OpAbort: conn = Info->LocalKey; conn->InfoSend = NULL; a_Chain_bcb(OpAbort, Info, NULL, NULL); Capi_conn_unref(conn); dFree(Info); break; default: MSG_WARN("Unused CCC\n"); break; } } else { /* 1 FWD */ /* Command sending branch (status) */ switch (Op) { case OpSend: if (!Data2) { MSG_WARN("Capi.c: Opsend [1F] Data2 = NULL\n"); } else if (strcmp(Data2, "FD") == 0) { conn = Info->LocalKey; conn->SockFD = *(int*)Data1; /* communicate the FD through the answer branch */ a_Capi_ccc(OpSend, 2, BCK, conn->InfoRecv, &conn->SockFD, "FD"); } else if (strcmp(Data2, "DpidOK") == 0) { /* resume pending dpi requests */ Capi_conn_resume(); } break; case OpAbort: conn = Info->LocalKey; conn->InfoSend = NULL; if (Data2) { if (!strcmp(Data2, "DpidERROR")) { a_UIcmd_set_msg(conn->bw, "ERROR: can't start dpid daemon " "(URL scheme = '%s')!", conn->url ? URL_SCHEME(conn->url) : ""); } else if (!strcmp(Data2, "Both") && conn->InfoRecv) { /* abort the other branch too */ a_Capi_ccc(OpAbort, 2, BCK, conn->InfoRecv, NULL, NULL); } } /* if URL == expect-url */ a_Nav_cancel_expect_if_eq(conn->bw, conn->url); /* finish conn */ Capi_conn_unref(conn); dFree(Info); break; default: MSG_WARN("Unused CCC\n"); break; } } } else if (Branch == 2) { if (Dir == BCK) { /* Answer branch */ switch (Op) { case OpStart: /* Data1 = conn; Data2 = {"http" | "<dpi server name>"} */ conn = Data1; Capi_conn_ref(conn); Info->LocalKey = conn; conn->InfoRecv = Info; a_Chain_link_new(Info, a_Capi_ccc, BCK, a_Dpi_ccc, 2, 2); a_Chain_bcb(OpStart, Info, NULL, Data2); break; case OpSend: /* Data1 = FD */ if (Data2 && strcmp(Data2, "FD") == 0) { a_Chain_bcb(OpSend, Info, Data1, Data2); } break; case OpAbort: conn = Info->LocalKey; conn->InfoRecv = NULL; a_Chain_bcb(OpAbort, Info, NULL, NULL); /* remove the cache entry for this URL */ a_Cache_entry_remove_by_url(conn->url); Capi_conn_unref(conn); dFree(Info); break; default: MSG_WARN("Unused CCC\n"); break; } } else { /* 2 FWD */ /* Server listening branch */ switch (Op) { case OpSend: conn = Info->LocalKey; if (strcmp(Data2, "send_page_2eof") == 0) { /* Data1 = dbuf */ DataBuf *dbuf = Data1; a_Cache_process_dbuf(IORead, dbuf->Buf, dbuf->Size, conn->url); } else if (strcmp(Data2, "send_status_message") == 0) { a_UIcmd_set_msg(conn->bw, "%s", Data1); } else if (strcmp(Data2, "chat") == 0) { a_UIcmd_set_msg(conn->bw, "%s", Data1); a_Bookmarks_chat_add(NULL, NULL, Data1); } else if (strcmp(Data2, "dialog") == 0) { a_Dpiapi_dialog(conn->bw, conn->server, Data1); } else if (strcmp(Data2, "reload_request") == 0) { a_Nav_reload(conn->bw); } else if (strcmp(Data2, "start_send_page") == 0) { /* prepare the cache to receive the data stream for this URL * * a_Capi_open_url() already added a new cache entry, * and a client for it. */ } break; case OpEnd: conn = Info->LocalKey; conn->InfoRecv = NULL; a_Cache_process_dbuf(IOClose, NULL, 0, conn->url); if (conn->InfoSend) { /* Propagate OpEnd to the sending branch too */ a_Capi_ccc(OpEnd, 1, BCK, conn->InfoSend, NULL, NULL); } Capi_conn_unref(conn); dFree(Info); break; default: MSG_WARN("Unused CCC\n"); break; } } } }