static int _sio_rpc_upstream_parse_response(struct sio *sio, struct sio_rpc_upstream *upstream) { struct sio_stream *stream = upstream->stream; struct sio_buffer *input = sio_stream_buffer(stream); uint64_t size; char *data= sio_buffer_data(input, &size); uint64_t used = 0; while (used < size) { uint64_t left = size - used; if (left < SHEAD_ENCODE_SIZE) break; /* header不完整 */ struct shead head; if (shead_decode(&head, data + used, SHEAD_ENCODE_SIZE) == -1) return -1; /* header不合法 */ if (left - SHEAD_ENCODE_SIZE < head.body_len) break; /* body不完整 */ void *value; if (shash_find(upstream->req_status, (const char *)&head.id, sizeof(head.id), &value) == 0) { /* 找到call */ assert(shash_erase(upstream->req_status, (const char *)&head.id, sizeof(head.id)) == 0); struct sio_rpc_request *req = value; if (head.type == req->type) { /* call的type相同, 回调用户, 关闭超时定时器, 释放call */ req->cb(upstream->client, 0, data + used + SHEAD_ENCODE_SIZE, head.body_len, req->arg); sio_stop_timer(sio, &req->timer); _sio_rpc_free_call(req); } else { /* 请求与应答的type不同, 客户端有bug才会至此, 作为超时处理 */ req->upstream = NULL; } } /* 没有找到对应的call, 忽略此应答 */ used += SHEAD_ENCODE_SIZE + head.body_len; } sio_buffer_erase(input, used); return 0; }
void sio_rpc_server_remove_method(struct sio_rpc_server *server, uint32_t type) { void *value; if (shash_find(server->methods, (const char *)&type, sizeof(type), &value) == -1) return; struct sio_rpc_method *method = value; free(method); }
void sio_rpc_server_add_method(struct sio_rpc_server *server, uint32_t type, sio_rpc_dstream_callback_t cb, void *arg) { if (shash_find(server->methods, (const char *)&type, sizeof(type), NULL) == 0) return; struct sio_rpc_method *method = malloc(sizeof(*method)); method->cb = cb; method->arg = arg; assert(shash_insert(server->methods, (const char *)&type, sizeof(type), method) == 0); }
static void _sio_rpc_dstream_handle_request(struct sio_rpc_dstream *dstream, const struct shead *head, const char *req) { void *value; if (shash_find(dstream->server->methods, (const char *)&head->type, sizeof(head->type), &value) == -1) return; struct sio_rpc_method *method = value; struct sio_rpc_response *resp = malloc(sizeof(*resp)); resp->conn_id = dstream->id; resp->server = dstream->server; memcpy(&resp->req_head, head, sizeof(*head)); resp->request = malloc(head->body_len); memcpy(resp->request, req, head->body_len); method->cb(dstream->server, resp, method->arg); }
void sio_rpc_finish(struct sio_rpc_response *resp, const char *body, uint32_t len) { struct sio_rpc_server *server = resp->server; void *value; if (shash_find(server->dstreams, (const char *)&resp->conn_id, sizeof(resp->conn_id), &value) == 0) { struct sio_rpc_dstream *dstream = value; struct shead resp_head; memcpy(&resp_head, &resp->req_head, sizeof(resp_head)); resp_head.body_len = len; char head[SHEAD_ENCODE_SIZE]; assert(shead_encode(&resp_head, head, sizeof(head)) == 0); int sent_head = sio_stream_write(server->rpc->sio, dstream->stream, head, sizeof(head)); int sent_body = sio_stream_write(server->rpc->sio, dstream->stream, body, len); if (sent_head != 0 && sent_body != 0) { /* response发送失败, 关闭连接 */ _sio_rpc_dstream_free(dstream); } } _sio_rpc_finish(resp); }
return(result); } static void tempd_unixctl_test(struct unixctl_conn *conn, int argc OVS_UNUSED, const char *argv[], void *aud OVS_UNUSED) { struct locl_sensor *sensor; int temp; const char *fan_name = argv[1]; struct shash_node *node; temp = atoi(argv[2]); // find the sensor structure node = shash_find(&sensor_data, fan_name); if (node == NULL) { unixctl_command_reply_error(conn, "Sensor does not exist"); return; } sensor = (struct locl_sensor *)node->data; // set the override value // -1 = no override, milidegrees centigrade, otherwise sensor->test_temp = temp; unixctl_command_reply(conn, "Test temperature override set"); } // initialize tempd process static void tempd_init(const char *remote)
static void parse_options(int argc, char *argv[], struct shash *local_options) { enum { OPT_DB = UCHAR_MAX + 1, OPT_ONELINE, OPT_NO_SYSLOG, OPT_DRY_RUN, OPT_PEER_CA_CERT, OPT_LOCAL, OPT_COMMANDS, OPT_OPTIONS, VLOG_OPTION_ENUMS, TABLE_OPTION_ENUMS }; static const struct option global_long_options[] = { {"db", required_argument, NULL, OPT_DB}, {"no-syslog", no_argument, NULL, OPT_NO_SYSLOG}, {"dry-run", no_argument, NULL, OPT_DRY_RUN}, {"oneline", no_argument, NULL, OPT_ONELINE}, {"timeout", required_argument, NULL, 't'}, {"help", no_argument, NULL, 'h'}, {"commands", no_argument, NULL, OPT_COMMANDS}, {"options", no_argument, NULL, OPT_OPTIONS}, {"version", no_argument, NULL, 'V'}, VLOG_LONG_OPTIONS, STREAM_SSL_LONG_OPTIONS, TABLE_LONG_OPTIONS, {NULL, 0, NULL, 0}, }; const int n_global_long_options = ARRAY_SIZE(global_long_options) - 1; char *tmp, *short_options; struct option *options; size_t allocated_options; size_t n_options; size_t i; tmp = ovs_cmdl_long_options_to_short_options(global_long_options); short_options = xasprintf("+%s", tmp); free(tmp); /* We want to parse both global and command-specific options here, but * getopt_long() isn't too convenient for the job. We copy our global * options into a dynamic array, then append all of the command-specific * options. */ options = xmemdup(global_long_options, sizeof global_long_options); allocated_options = ARRAY_SIZE(global_long_options); n_options = n_global_long_options; ctl_add_cmd_options(&options, &n_options, &allocated_options, OPT_LOCAL); table_style.format = TF_LIST; for (;;) { int idx; int c; c = getopt_long(argc, argv, short_options, options, &idx); if (c == -1) { break; } switch (c) { case OPT_DB: db = optarg; break; case OPT_ONELINE: oneline = true; break; case OPT_NO_SYSLOG: vlog_set_levels(&this_module, VLF_SYSLOG, VLL_WARN); break; case OPT_DRY_RUN: dry_run = true; break; case OPT_LOCAL: if (shash_find(local_options, options[idx].name)) { ctl_fatal("'%s' option specified multiple times", options[idx].name); } shash_add_nocopy(local_options, xasprintf("--%s", options[idx].name), optarg ? xstrdup(optarg) : NULL); break; case 'h': usage(); case OPT_COMMANDS: ctl_print_commands(); case OPT_OPTIONS: ctl_print_options(global_long_options); case 'V': ovs_print_version(0, 0); printf("DB Schema %s\n", sbrec_get_db_version()); exit(EXIT_SUCCESS); case 't': timeout = strtoul(optarg, NULL, 10); if (timeout < 0) { ctl_fatal("value %s on -t or --timeout is invalid", optarg); } break; VLOG_OPTION_HANDLERS TABLE_OPTION_HANDLERS(&table_style) STREAM_SSL_OPTION_HANDLERS case '?': exit(EXIT_FAILURE); default: abort(); } } free(short_options); if (!db) { db = sbctl_default_db(); } for (i = n_global_long_options; options[i].name; i++) { free(CONST_CAST(char *, options[i].name)); } free(options); }
/* * Function : udpfwd_relay_to_dhcp_client * Responsibilty : Send DHCP replies to client. * This routine relays a DHCP reply to the client which * generated the initial request. The routine accesses * global pointers already set to indicate the reply. * All messages are discarded after the hops field exceeds * 16 to comply with the relay agent behavior specified * in RFC 1542. The relay agent normally discards such messages * before this routine is called. They will only be received by * this routine if the user ignores the instructions * in the manual and sets the value of DHCP_MAX_HOPS higher than 16. * * Params: void* pkt - packet * size - size of udp payload * in_pktinfo *pktInfo - pktInfo structure * * Returns: void */ void udpfwd_relay_to_dhcp_client(void* pkt, int32_t size, struct in_pktinfo *pktInfo) { struct ip *iph; /* ip header */ struct udphdr *udph; /* udp header */ struct dhcp_packet *dhcp; /* dhcp header */ struct arpreq arp_req; unsigned char *option = NULL; /* Dhcp options. */ bool NAKReply = false; /* Whether this is a NAK. */ struct sockaddr_in dest; uint32_t ifIndex = -1; char ifName[IF_NAMESIZE + 1]; struct in_addr interface_ip_address; /* Interface IP address. */ DHCP_OPTION_82_OPTIONS option82_info; struct shash_node *node; UDPFWD_INTERFACE_NODE_T *intfNode = NULL; OPTION82_RESULT_t option82_result; iph = (struct ip *) pkt; udph = (struct udphdr *) ((char *)iph + (iph->ip_hl * 4)); dhcp = (struct dhcp_packet *) ((char *)iph + (iph->ip_hl * 4) + UDPHDR_LENGTH); interface_ip_address.s_addr = dhcp->giaddr.s_addr; /* Get ifIndex associated with this Interface IP address. */ ifIndex = getIfIndexfromIpAddress(interface_ip_address.s_addr); /* Get ifname from ifindex */ if ((-1 == ifIndex) || (NULL == if_indextoname(ifIndex, ifName))) { VLOG_ERR("Failed to read input interface : %d", ifIndex); return; } iph->ip_ttl--; /* Acquire db lock */ sem_wait(&udpfwd_ctrl_cb_p->waitSem); node = shash_find(&udpfwd_ctrl_cb_p->intfHashTable, ifName); if (NULL == node) { /* Release db lock */ sem_post(&udpfwd_ctrl_cb_p->waitSem); return; } intfNode = (UDPFWD_INTERFACE_NODE_T *)node->data; /* initialize option82_info struct */ memset(&option82_info, 0, sizeof(option82_info)); option82_result = process_dhcp_relay_option82_message(pkt, &option82_info, ifIndex, ifName, 0); if (option82_result == DROPPED) { VLOG_ERR("Option 82 check failed when relaying packet to client." "Drop packet"); INC_UDPF_DHCPR_OPT82_SERVER_DROPS(intfNode); /* Release the semaphore and return */ sem_post(&udpfwd_ctrl_cb_p->waitSem); return; } else if (option82_result == VALID) INC_UDPF_DHCPR_OPT82_SERVER_SENT(intfNode); /* Check whether this packet is a NAK. */ option = dhcpPickupOpt(dhcp, DHCP_PKTLEN(udph), DHCP_MSGTYPE); if (option != NULL) NAKReply = (*OPTBODY (option) == DHCPNAK); /* Examine broadcast flag. */ if((ntohs(dhcp->flags) & UDPFWD_DHCP_BROADCAST_FLAG)|| NAKReply) /* Broadcast flag is set or a NAK, so set MAC address to broadcast. */ { /* Set destination IP address to broadcast address. */ dest.sin_addr.s_addr = IP_ADDRESS_BCAST; dest.sin_port = htons(DHCPC_PORT); dest.sin_family = AF_INET; } else { /* * By default use these following for dest IP and MAC * By default set MAC address to server MAC address. */ /* By default set destination IP address offered address. */ dest.sin_addr.s_addr = dhcp->yiaddr.s_addr; dest.sin_port = htons(DHCPC_PORT); dest.sin_family = AF_INET; /* * DHCP ACK message workaround: * Windows server uses DHCP Inform and ACK mssages to discover * other DHCP Servers on the network. * The ACK message will have the yiaddr set to 0.0.0.0 and * chaddr field set to 0. In this case use the ciaddr field * and check for the ARP table for the client MAC address. */ if ((option != NULL) && (*OPTBODY (option) == DHCPACK)) { if (dhcp->yiaddr.s_addr == IP_ADDRESS_NULL) { if(dhcp->ciaddr.s_addr != IP_ADDRESS_NULL) dest.sin_addr.s_addr = dhcp->ciaddr.s_addr; else { /* ciaddr is 0.0.0.0, don't relay to client. */ INC_UDPF_DHCPR_SERVER_DROPS(intfNode); sem_post(&udpfwd_ctrl_cb_p->waitSem); return; } } } strncpy(arp_req.arp_dev, ifName, IF_NAMESIZE); memcpy(&arp_req.arp_pa, &dest, sizeof(struct sockaddr_in)); arp_req.arp_ha.sa_family = dhcp->htype; memcpy(arp_req.arp_ha.sa_data, dhcp->chaddr, dhcp->hlen); arp_req.arp_flags = ATF_COM; if (ioctl(udpfwd_ctrl_cb_p->udpSockFd, SIOCSARP, &arp_req) == -1) VLOG_ERR("ARP Failed, errno value = %d", errno); } pktInfo->ipi_ifindex = ifIndex; pktInfo->ipi_spec_dst.s_addr = 0; /* update value of size */ size = ntohs(iph->ip_len); if (udpfwd_send_pkt_through_socket((void*)pkt, size, pktInfo, &dest) != true) { VLOG_ERR("Failed to send packet dhcp-client"); INC_UDPF_DHCPR_SERVER_DROPS(intfNode); } else { INC_UDPF_DHCPR_SERVER_SENT(intfNode); } sem_post(&udpfwd_ctrl_cb_p->waitSem); return; }
/* * Function: udpfwd_relay_to_dhcp_server * Responsibilty : Send incoming DHCP message to client port. * This routine relays a DHCP message to the client port of * every DHCP server or relay agent whose IP address is * contained in the interface structure. All messages are * discarded after the hops field exceeds 16 to comply with * the relay agent behavior specified in RFC 1542. * The relay agent normally discards such messages before * this routine is called. They will only be received by this * routine if the user ignores the instructions in the * manual and sets the value of DHCP_MAX_HOPS higher than 16. * Parameters : pkt - ip packet * size - size of udp payload * pktInfo - pktInfo structure * Returns: void * */ void udpfwd_relay_to_dhcp_server(void* pkt, int32_t size, struct in_pktinfo *pktInfo) { struct ip *iph; /* ip header */ struct udphdr *udph; /* udp header */ struct dhcp_packet* dhcp; IP_ADDRESS interface_ip; int32_t iter = 0; uint32_t ifIndex = -1; struct sockaddr_in to; struct shash_node *node; UDPFWD_SERVER_T *server = NULL; UDPFWD_SERVER_T **serverArray = NULL; UDPFWD_INTERFACE_NODE_T *intfNode = NULL; char ifName[IF_NAMESIZE + 1]; DHCP_OPTION_82_OPTIONS option82_info; OPTION82_RESULT_t option82_result; ifIndex = pktInfo->ipi_ifindex; if ((-1 == ifIndex) || (NULL == if_indextoname(ifIndex, ifName))) { VLOG_ERR("Failed to read input interface : %d", ifIndex); return; } /* Get IP address associated with the Interface. */ interface_ip = getLowestIpOnInterface(ifName); /* If there is no IP address on the input interface do not proceed. */ if(interface_ip == 0) { VLOG_ERR("%s: Interface IP address is 0. Discard packet", ifName); return; } iph = (struct ip *) pkt; udph = (struct udphdr *) ((char *)iph + (iph->ip_hl * 4)); dhcp = (struct dhcp_packet *) ((char *)iph + (iph->ip_hl * 4) + UDPHDR_LENGTH); if ((dhcp->hops) > UDPFWD_DHCP_MAX_HOPS) { VLOG_ERR("Hops field exceeds %d as a result packet is discarded\n", UDPFWD_DHCP_MAX_HOPS); return; } /* ======================================================================== Make the appropriate port correction http://www.ietf.org/internet-drafts/draft-ietf-dhc-implementation-02.txt 4.7.2 Relay Agent Port Usage Relay agents should use port 67 as the source port number. Relay agents always listen on port 67, but port 68 has sometimes used as the source port number probably because it was copied from the source port of the incoming packet. Cable modem vendors would like to install filters blocking outgoing packets with source port 67. RECOMMENDATIONS: O Relay agents MUST use 67 as their source port number. O Relay agents MUST NOT forward packets with non-zero giaddr unless the source port number on the packet is 67. ===================================================================== */ if (udph->uh_sport == DHCPC_PORT) udph->uh_sport = DHCPS_PORT; /* Acquire db lock */ sem_wait(&udpfwd_ctrl_cb_p->waitSem); node = shash_find(&udpfwd_ctrl_cb_p->intfHashTable, ifName); if (NULL == node) { /* Release db lock */ sem_post(&udpfwd_ctrl_cb_p->waitSem); return; } if (ENABLE == get_feature_status(udpfwd_ctrl_cb_p->feature_config.config, DHCP_RELAY_HOP_COUNT_INCREMENT)) { dhcp->hops++; } /* RFC prefers to decrement time to live */ iph->ip_ttl--; intfNode = (UDPFWD_INTERFACE_NODE_T *)node->data; memset(&option82_info, 0, sizeof(option82_info)); option82_info.ip_addr = interface_ip; option82_result = process_dhcp_relay_option82_message(pkt, &option82_info, ifIndex, ifName, intfNode->bootp_gw); if (option82_result == DROPPED) { VLOG_ERR("Option 82 check failed when relaying packet to server." "Drop packet"); INC_UDPF_DHCPR_OPT82_CLIENT_DROPS(intfNode); /* Release the semaphore and return */ sem_post(&udpfwd_ctrl_cb_p->waitSem); return; } else if (option82_result == VALID) INC_UDPF_DHCPR_OPT82_CLIENT_SENT(intfNode); /* * we need to preserve the giaddr in case of multi hop relays * so setting a giaddr should be done only when giaddr is zero. */ if (dhcp->giaddr.s_addr == 0) { /* Check if Bootp Gateway configured on this interface is valid one * and if yes, use this for stamping the DHCP requests */ if (intfNode->bootp_gw && (ipExistsOnInterface(ifName, intfNode->bootp_gw))) { dhcp->giaddr.s_addr = intfNode->bootp_gw; } else dhcp->giaddr.s_addr = interface_ip; } /* update value of size */ size = ntohs(iph->ip_len); serverArray = intfNode->serverArray; /* Relay DHCP-Request to each of the configured server. */ for(iter = 0; iter < intfNode->addrCount; iter++) { server = serverArray[iter]; if (server->udp_port != DHCPS_PORT) { continue; } if ( iph->ip_src.s_addr == INADDR_ANY) { /* * If the source IP address is 0, then replace the ip address with * IP addresss of the interface on which the packet is received. */ iph->ip_src.s_addr = interface_ip; } pktInfo->ipi_ifindex = 0; to.sin_family = AF_INET; to.sin_addr.s_addr = server->ip_address; to.sin_port = htons(DHCPS_PORT); if (udpfwd_send_pkt_through_socket((void*)pkt, size, pktInfo, &to) == true) { INC_UDPF_DHCPR_CLIENT_SENT(intfNode); VLOG_INFO("packet sent to server successfully\n\n"); } else { VLOG_ERR("failed to send packet to server\n\n"); INC_UDPF_DHCPR_CLIENT_DROPS(intfNode); } } /* Release db lock */ sem_post(&udpfwd_ctrl_cb_p->waitSem); return; }
/* * Function: udpfwd_forward_packet * Responsibilty : Send incoming UDP broadcast message to server UDP port. * This routine forwards the UDP broadcast message to the * UDP port of configured destination UDP server. * Parameters : pkt - Ip packet * udp_dport - destination udp port * size - size of udp payload * pktInfo - pktInfo structure * Returns: void * */ void udpfwd_forward_packet (void *pkt, uint16_t udp_dport, int32_t size, struct in_pktinfo *pktInfo) { IP_ADDRESS interface_ip; uint32_t iter = 0; uint32_t ifIndex = -1; char ifName[IF_NAMESIZE + 1]; struct sockaddr_in to; struct shash_node *node; UDPFWD_SERVER_T *server = NULL; UDPFWD_SERVER_T **serverArray = NULL; UDPFWD_INTERFACE_NODE_T *intfNode = NULL; ifIndex = pktInfo->ipi_ifindex; if ((-1 == ifIndex) || (NULL == if_indextoname(ifIndex, ifName))) { VLOG_ERR("Failed to read input interface : %d", ifIndex); return; } /* Get IP address associated with the Interface. */ interface_ip = getLowestIpOnInterface(ifName); /* If there is no IP address on the input interface do not proceed. */ if(interface_ip == 0) { VLOG_ERR("interface IP address is 0. Discard packet"); return; } /* Acquire db lock */ sem_wait(&udpfwd_ctrl_cb_p->waitSem); node = shash_find(&udpfwd_ctrl_cb_p->intfHashTable, ifName); if (NULL == node) { VLOG_DBG("packet from client on interface %s without " "UDP forward-protocol address\n", ifName); /* Release db lock */ sem_post(&udpfwd_ctrl_cb_p->waitSem); return; } intfNode = (UDPFWD_INTERFACE_NODE_T *)node->data; serverArray = intfNode->serverArray; /* UDP Broadcast Forwarder request to each of the configured server. */ for(iter = 0; iter < intfNode->addrCount; iter++) { server = serverArray[iter]; if (server->udp_port != udp_dport) { continue; } if ( pktInfo->ipi_addr.s_addr == INADDR_ANY) { /* If the source IP address is 0, then replace the ip address with * IP addresss of the interface on which the packet is received. */ pktInfo->ipi_spec_dst.s_addr = interface_ip; } pktInfo->ipi_ifindex = 0; to.sin_family = AF_INET; to.sin_addr.s_addr = server->ip_address; to.sin_port = htons(udp_dport); if (udpfwd_send_pkt_through_socket(pkt, size, pktInfo, &to) == true) { VLOG_INFO("packet sent to server successfully\n\n"); } } /* Release db lock */ sem_post(&udpfwd_ctrl_cb_p->waitSem); return; }