int tcpclient_sendall(tcpclient_t *client, const char *buf, size_t len) { buffer_t *sendq = &client->send_queue; if (client->addr == NULL) { stats_error_log("tcpclient[%s]: Cannot send before connect!", client->name); return 1; } else { // Does nothing if we're already connected, triggers a // reconnect if backoff has expired. tcpclient_connect(client); } if (buffer_datacount(&client->send_queue) >= client->config->max_send_queue) { if (client->failing == 0) { stats_error_log("tcpclient[%s]: send queue for %s client is full (at %zd bytes, max is %" PRIu64 " bytes), dropping data", client->name, tcpclient_state_name[client->state], buffer_datacount(&client->send_queue), client->config->max_send_queue); client->failing = 1; } return 2; } if (buffer_spacecount(sendq) < len) { if (buffer_realign(sendq) != 0) { stats_error_log("tcpclient[%s]: Unable to realign send queue", client->name); return 3; } } while (buffer_spacecount(sendq) < len) { if (buffer_expand(sendq) != 0) { stats_error_log("tcpclient[%s]: Unable to allocate additional memory for send queue, dropping data", client->name); return 4; } } memcpy(buffer_tail(sendq), buf, len); buffer_produced(sendq, len); if (client->state == STATE_CONNECTED) { client->write_watcher.started = true; ev_io_start(client->loop, &client->write_watcher.watcher); } return 0; }
//----------------------------------------------------------------------------- NetworkType* new_tcp_client_state( char* ip, int port, uint32_t *ticks) { NetworkType *tcp = malloc(sizeof(NetworkType)); tcp->tick = tick; tcp->logic_tick = logic_tick; tcp->add_command = add_command; tcp->get_command = get_command; tcp->get_id = get_id; tcp->cleanup = cleanup; TcpClientState *state = (TcpClientState *) malloc(sizeof(TcpClientState)); memset(state, 0, sizeof(TcpClientState)); tcp->state = (void *)state; state->msg_size = 0; state->in = new_queue(1); state->out = new_queue(1); state->last_post_time = 0; state->post_delay = 0.12; state->waiting = 0; state->client_id = -1; state->ready = 0; state->read_buf = malloc(1); state->ticks = ticks; state->socket = new_tcpclient(); tcpclient_init(state->socket, port, ip); tcpclient_set_user_data(state->socket, tcp->state); printf("Connecting...\n"); tcpclient_set_handlers(state->socket, &client_read, &client_disconnect); tcpclient_connect(state->socket); return tcp; }
/* parsing lists {{{*/ if(service) { xmlNodePtr memberships = findNode(service->children, "Memberships", 1); xmlNodePtr ms; xmlNodePtr role; xmlNodePtr members, member; xmlNodePtr pname; xmlNodePtr type; xmlNodePtr lastchange; xmlChar *content; int flag = 0; lastchange = findNode(service->children, "LastChange", 1); content = xmlNodeGetContent(lastchange); cl->lastchange = strdup((char*)content); DMSG(stderr, "Contact: lastchange = %s\n", cl->lastchange); if(!memberships) { fprintf(stderr, "NULL membership\n"); count = 0; goto cleanup; } for(ms=memberships->children;ms;ms=ms->next) { int ctype = 1; if(!ms->children) continue; role = findNode(ms->children, "MemberRole", 1); if(!role) { fprintf(stderr, "Null role\n"); count = 0; goto cleanup; } members = findNode(role, "Members", 1); if(!members) continue; if(xmlStrEqual(role->children->content, (xmlChar*)"Allow")) flag = 3; else if(xmlStrEqual(role->children->content, (xmlChar*)"Block")) flag = 4; else continue; for(member=members->children;member;member=member->next) { Contact *c; type = findNode(member->children, "Type", 1); content = xmlNodeGetContent(type); if(!content) { fprintf(stderr, "NULL Type\n"); continue; } if(xmlStrEqual(content, (xmlChar*)"Passport")) { pname = findNode(member->children, "PassportName", 1); ctype = 1; } else if(xmlStrEqual(content, (xmlChar*)"Email")) { pname = findNode(member->children, "Email", 1); ctype = 32; } else continue; xmlFree(content); if(!pname) { fprintf(stderr, "NULL PassportName or Email\n"); continue; } content = xmlNodeGetContent(pname); if(content) { char name[32]; char domain[32]; if(sscanf((char*)content, "%[^@]@%s", name, domain) != 2) { fprintf(stderr, "parse contact: malformed email: %s\n", content); continue; } c = contact_new((char*)content); c->name = strdup(name); c->type = ctype; c->status = NA; c->inlist |= flag; c->domain = NULL; /* should be filled during sort */ cl_append_contact(cl, c, name, domain); xmlFree(content); count++; } } } }/*}}}*/ DMSG(stderr, "parsed contact count: %d\n", count); cleanup: cl->flag &= ~CL_INITLIST; return count; }/*}}}*/ int _cl_do_soapreq_ab(CL *cl)/*{{{*/ { TCPClient *client; char *req = NULL; char *header; char buf[512]; int ret, len; char *ptr = NULL; client = tcpclient_new("contacts.msn.com", 80); ret = _cl_load_soapreq_ab(cl, cl->ablastchange, &req, TRUE); if(ret) { tcpclient_connect(client); header = (char*)xmalloc(strlen(ab_request_header) + 32); DMSG(stderr, "sending ab request\n"); len = sprintf(header, "%s%d\r\n\r\n", ab_request_header, ret); if(tcpclient_send(client, header, len) <= 0) goto cleanup; if(tcpclient_send(client, req, ret) <= 0) goto cleanup; len = tcpclient_recv_header(client, &ptr); /* header */ if(ptr) { HTTPHeader *header; xmlDocPtr doc; xmlParserCtxtPtr ctxt; FILE *fp; DMSG(stderr, "AB response header:\n%s", ptr); header = http_parse_header(ptr); len = header->content_length; DMSG(stderr, "Length: %d\n", len); http_header_destroy(header); memset(buf, 0, sizeof(buf)); fp = fopen("addressbook.xml", "w"); fprintf(fp, buf); len -= (ret = tcpclient_recv(client, buf, sizeof(buf)-1)); ctxt = xmlCreatePushParserCtxt(NULL, NULL, buf, ret, "addressbook.xml"); fprintf(fp, buf); if(ctxt == NULL) { fprintf(stderr, "failed to create parser context"); return 0; } while(len > 0) { memset(buf, 0, sizeof(buf)); len -= (ret=tcpclient_recv(client, buf, sizeof(buf)-1)); fprintf(fp, buf); xmlParseChunk(ctxt, buf, ret, 0); } fclose(fp); xmlParseChunk(ctxt, buf, 0, 1); tcpclient_destroy(client); client = NULL; doc = ctxt->myDoc; len = ctxt->wellFormed; xmlFreeParserCtxt(ctxt); //count += _cl_parse_contacts(cl, doc); xmlFreeDoc(doc); xmlCleanupParser(); DMSG(stderr, "addressbook xml parsing done: %s\n", len?"good":"malformed"); xfree(ptr); } else { DMSG(stderr, "ab: no header found\n\r"); } } else { fprintf(stderr, "failed to load abreq\n"); } cleanup: xfree(header); return 0; }/*}}}*/
int tcpclient_connect(tcpclient_t *client) { struct addrinfo hints; struct addrinfo *addr; int sd; if (client->state == STATE_CONNECTED || client->state == STATE_CONNECTING) { // Already connected, do nothing return 1; } if (client->state == STATE_BACKOFF) { // If backoff timer has expired, change to STATE_INIT and call recursively if ((time(NULL) - client->last_error) > TCPCLIENT_RETRY_TIMEOUT) { tcpclient_set_state(client, STATE_INIT); return tcpclient_connect(client); } else { return 2; } } if (client->state == STATE_INIT) { // Resolve address, create socket, set nonblocking, setup callbacks, fire connect if (client->config->always_resolve_dns == true && client->addr != NULL) { freeaddrinfo(client->addr); client->addr = NULL; } if (client->addr == NULL) { // We only know about tcp and udp, so if we get something unexpected just // default to tcp if (strncmp(client->protocol, "udp", 3) == 0) { client->socktype = SOCK_DGRAM; } else { client->socktype = SOCK_STREAM; } memset(&hints, 0, sizeof(hints)); hints.ai_family = AF_UNSPEC; hints.ai_socktype = client->socktype; hints.ai_flags = AI_PASSIVE; if (getaddrinfo(client->host, client->port, &hints, &addr) != 0) { stats_error_log("tcpclient: Error resolving backend address %s: %s", client->host, gai_strerror(errno)); client->last_error = time(NULL); tcpclient_set_state(client, STATE_BACKOFF); client->callback_error(client, EVENT_ERROR, client->callback_context, NULL, 0); return 3; } client->addr = addr; snprintf(client->name, TCPCLIENT_NAME_LEN, "%s/%s/%s", client->host, client->port, client->protocol); } else { addr = client->addr; } if ((sd = socket(addr->ai_family, addr->ai_socktype, addr->ai_protocol)) < 0) { stats_error_log("tcpclient[%s]: Unable to create socket: %s", client->name, strerror(errno)); client->last_error = time(NULL); tcpclient_set_state(client, STATE_BACKOFF); client->callback_error(client, EVENT_ERROR, client->callback_context, NULL, 0); return 4; } #ifdef TCP_CORK if (client->config->enable_tcp_cork && addr->ai_family == AF_INET && addr->ai_socktype == SOCK_STREAM && addr->ai_protocol == IPPROTO_TCP) { int state = 1; if (setsockopt(sd, IPPROTO_TCP, TCP_CORK, &state, sizeof(state))) { stats_error_log("failed to set TCP_CORK"); } } #endif client->sd = sd; if (fcntl(sd, F_SETFL, (fcntl(sd, F_GETFL) | O_NONBLOCK)) != 0) { stats_error_log("tcpclient[%s]: Unable to set socket to non-blocking: %s", client->name, strerror(errno)); client->last_error = time(NULL); tcpclient_set_state(client, STATE_BACKOFF); close(sd); client->callback_error(client, EVENT_ERROR, client->callback_context, NULL, 0); return 5; } client->connect_watcher.started = true; client->connect_watcher.watcher.data = client; client->timeout_watcher.data = client; ev_io_init(&client->connect_watcher.watcher, tcpclient_connected, sd, EV_WRITE); ev_io_start(client->loop, &client->connect_watcher.watcher); ev_timer_set(&client->timeout_watcher, TCPCLIENT_CONNECT_TIMEOUT, 0); ev_timer_start(client->loop, &client->timeout_watcher); if (connect(sd, addr->ai_addr, addr->ai_addrlen) != 0 && errno != EINPROGRESS) { stats_error_log("tcpclient[%s]: Unable to connect: %s", client->name, strerror(errno)); client->last_error = time(NULL); tcpclient_set_state(client, STATE_BACKOFF); ev_timer_stop(client->loop, &client->timeout_watcher); ev_io_stop(client->loop, &client->connect_watcher.watcher); close(sd); client->callback_error(client, EVENT_ERROR, client->callback_context, NULL, 0); return 6; } tcpclient_set_state(client, STATE_CONNECTING); return 0; } stats_error_log("tcpclient[%s]: Connect with unknown state %i", client->name, client->state); return 7; }