// Support. Do we support this protocol? void incoming_request(mapping info) { if(!ACCESS_CHECK(previous_object())) return; if (stringp(info["NAME"]) && stringp(info["PORTUDP"])) { // dont want requests from ourself if(info["NAME"] == Mud_name()) return; if(!DNS_MASTER->dns_mudp(info["NAME"])) PING_Q->send_ping_q(info["HOSTADDRESS"], info["PORTUDP"]); // if the file exists that is enough to know that we support // it, unless there is a param request, in which case we have // to call_other to the file to check. if( file_size(AUX_PATH+info["CMD"]+".c") <= 0 || (!undefinedp(info["PARAM"]) && call_other(AUX_PATH+info["CMD"], "support_"+info["PARAM"]))) { // we don't support it DNS_MASTER->send_udp(info["HOSTADDRESS"], info["PORTUDP"], sprintf("@@@%s||NAME:%s||PORTUDP:%d||CMD:%s||NOTSUPPORTED:yes||ANSWERID:%s@@@\n", DNS_SUPPORT_A, Mud_name(), udp_port(), info["CMD"]+ (!undefinedp(info["PARAM"]) ? "||PARAM:"+info["PARAM"] : ""), info["ANSWERID"])); } else { // we do support it DNS_MASTER->send_udp(info["HOSTADDRESS"], info["PORTUDP"], sprintf("@@@%s||NAME:%s||PORTUDP:%d||CMD:%s||SUPPORTED:yes||ANSWERID:%s@@@\n", DNS_SUPPORT_A, Mud_name(), udp_port(), info["CMD"]+(!undefinedp(info["PARAM"]) ? "||PARAM:"+info["PARAM"] : ""), info["ANSWERID"])); } } //if (stringp(info["NAME"]) && stringp(info["PORTUDP"])) }
// Returns 0 for success, WSAGetLastError() otherwise. int NetAPI_::Init() { if (init) return 0; // initialze winsock int ret = WSAStartup(MAKEWORD(2,2), &wsData); if (ret) { Error er = CreateError(Error::E_NetworkInit); throw er; } // Save local IP address for later convience. localIP = inet_ntoa(*(in_addr*)*gethostbyname("")->h_addr_list); init = true; Config config( "..\\Data\\Config.txt" );\ unsigned low = config.range_.low_; unsigned high = config.range_.high_; while (low <= high) udp_ports.push_back(udp_port(low++,false)); return 0; }
// This is the interface to the intermud channels void send_remote_q(string mud,string channel,string me,string who,string msg) { mapping rhost; if( !this_player() || !ACCESS_CHECK(previous_object())) return; mud = htonn( mud ); if (mud == mud_nname()) return; rhost = (mapping)DNS_MASTER->query_mud_info(mud); if (!rhost) return ; msg = replace_string(msg, "|", ""); msg = replace_string(msg, "@@@", ""); #ifdef DEBUG CHANNEL_D->do_channel(this_object(), DEBUG, sprintf("send remote to host %s channel %s\n message (%s %s %s).", mud, channel, me, msg, who)); #endif DNS_MASTER->send_udp(rhost["HOSTADDRESS"], rhost["PORTUDP"], "@@@" + "remote_q" + "||NAME:" + Mud_name() + "||PORTUDP:" + udp_port() + "||CHANNEL:" + channel + "||SOURCE_ID:" + lower_case(me) + "||TARGET_ID:" + lower_case(who) + "||MSG:" + msg+"@@@\n"); }
int send_gtell(string mud, string wiz_to, object source, string msg) { mapping minfo; if (! ACCESS_CHECK(previous_object()) && is_root(previous_object())) return 0; mud = htonn(mud); if (mud == mud_nname() || ! source) return 0; minfo = (mapping)DNS_MASTER->query_mud_info(mud); if (! minfo) { write(LOCAL_MUD_NAME() + "并没有和 " + mud + " 联系上。\n"); return 0; } msg = replace_string(msg, "|", ""); msg = replace_string(msg, "@@@", ""); DNS_MASTER->send_udp(minfo["HOSTADDRESS"], minfo["PORTUDP"], "@@@" + DNS_GTELL + "||NAME:" + Mud_name() + "||PORTUDP:" + udp_port() + "||WIZTO:" + wiz_to + "||WIZFROM:" + capitalize(source->query("id")) + "||CNAME:" + source->name(1) + "||WIZ_LEVEL:" + wiz_level(source) + "||MSG:" + msg + "@@@\n"); return 1; }
void send_gtell(string mud, string wiz_to, object source, string msg) { mapping minfo; if(!ACCESS_CHECK(previous_object()) && base_name(previous_object()) != TELL_CMD) return; mud = htonn( mud ); if(mud == mud_nname() || !geteuid(source)) return; minfo = (mapping)DNS_MASTER->query_mud_info(mud); if (!minfo) return ; msg = replace_string(msg, "|", ""); msg = replace_string(msg, "@@@", ""); DNS_MASTER->send_udp(minfo["HOSTADDRESS"], minfo["PORTUDP"], "@@@" + DNS_GTELL + "||NAME:" + Mud_name() + "||PORTUDP:" + udp_port() + "||WIZTO:" + wiz_to + "||WIZFROM:" + capitalize(geteuid(source)) + "||CNAME:" + source->name(1) + "||MSG:"+msg+"@@@\n"); }
void create() { seteuid(ROOT_UID); my_address = query_host_name(); my_port = udp_port(); set("channel_id", "Íø·»ØÓ¦¾«Áé"); }
// send a pinq query void send_ping_q(string host, mixed port) { if(!ACCESS_CHECK(previous_object())) return; DNS_MASTER->send_udp(host, port, "@@@"+DNS_PING_Q+ "||NAME:"+Mud_name()+ "||PORTUDP:"+udp_port()+ "@@@\n"); }
// we send this when we shut down void send_shutdown(string host, int port) { if(!ACCESS_CHECK(previous_object())) return; DNS_MASTER->send_udp(host, port, "@@@"+DNS_SHUTDOWN+ "||NAME:"+Mud_name()+ "||PORTUDP:"+udp_port()+ "@@@\n"); }
void send_support_q(string host, mixed port, string cmd, string param) { int idx; function f; if(!ACCESS_CHECK(previous_object())) return; if (!param) param = ""; f = (: previous_object(), "support_q_callback" :); idx = index_add(f); DNS_MASTER->send_udp(host, port, sprintf("@@@%s||NAME:%s||PORTUDP:%d||CMD:%s||ANSWERID:%d@@@\n", DNS_SUPPORT_Q, Mud_name(), udp_port(), cmd + (strlen(param) ? "||PARAM:"+param : ""), idx)); }
// send a pinq query void send_ping_q(string host, mixed port) { /* CHANNEL_D->do_channel(this_object(), "sys", "send_ping "+ host+" "+port+" (from "+Mud_name()+")"); return; //don't ping */ if(!ACCESS_CHECK(previous_object())) return; DNS_MASTER->send_udp(host, port, "@@@"+DNS_PING_Q+ "||NAME:"+Mud_name()+ "||PORTUDP:"+udp_port()+ "@@@\n"); }
void send_affirmation_a(string host, string port, string from, string to, string msg, string type) { // if(!ACCESS_CHECK(previous_object())) return; DNS_MASTER->send_udp(host, port, "@@@"+DNS_AFFIRMATION_A+ "||NAME:"+Mud_name()+ "||PORTUDP:"+udp_port()+ "||WIZTO:"+to+ "||WIZFROM:"+from+ "||TYPE:"+type+ "||MSG:"+msg+"@@@\n"); }
// This is the interface to the intermud channels void send_msg(string channel, string id, string name, string msg, int emoted, mixed filter) { string *names; int i; mapping muds; mapping svcs; mapping minfo; if( !this_player() // Prevent from being called by ourself. || !ACCESS_CHECK(previous_object())) return; #ifdef DEBUG set("channel_id", "网路频道精灵"); CHANNEL_D->do_channel(this_object(), "sys", "prepare to send gchannel message."); #endif muds = (mapping)DNS_MASTER->query_muds(); svcs = (mapping)DNS_MASTER->query_svc(); msg = replace_string(msg, "|", ""); msg = replace_string(msg, "@@@", ""); // use keys(svcs) because none of the muds not in svcs can possibley // receive the message names = keys(svcs); i = sizeof(names); while(i--) if( (names[i] != mud_nname()) && evaluate(filter, muds[names[i]]) && (muds[names[i]]["MUDLIB"]=="Eastern Stories" || muds[names[i]]["MUDLIB"]=="A Journey to the West") ) { minfo = muds[names[i]]; if(!mapp(minfo) || !mapp(svcs[names[i]]) || !(svcs[names[i]]["gwizmsg"] & SVC_UDP)) continue; #ifdef DEBUG set("channel_id", "网路频道精灵"); CHANNEL_D->do_channel(this_object(), "sys", sprintf("gchannel message sent to %s.", minfo["NAME"])); #endif DNS_MASTER->send_udp(minfo["HOSTADDRESS"], minfo["PORTUDP"], "@@@" + DNS_GCHANNEL + "||NAME:" + Mud_name() + "||PORTUDP:" + udp_port() + "||USRNAME:" + capitalize(id) + "||CNAME:" + name + "||MSG:" + msg + "||CHANNEL:" + channel + (emoted?"||EMOTE:1":"") + "@@@\n"); } }
void incoming_request(mapping info) { string field; if(!info["NAME"] || !info["PORTUDP"]) return; if(!DNS_MASTER->query_mud_info(info["NAME"])) PING_Q->send_ping_q(info["HOSTADDRESS"], info["PORTUDP"]); if(!info["TARGET"]) field = "NO"; else field = (find_player(lower_case(info["TARGET"])) ? "YES" : "NO"); DNS_MASTER->send_udp(info["HOSTADDRESS"], info["PORTUDP"], "@@@"+DNS_LOCATE_A+"||NAME:"+Mud_name()+ "||PORTUDP:"+udp_port()+ "||LOCATE:"+field+ "||TARGET:"+info["TARGET"]+ "||ASKWIZ:"+info["ASKWIZ"]+"@@@\n"); }
void incoming_request(mapping info) { mapping rhost; object ob; if(!ACCESS_CHECK(previous_object())) return; if (undefinedp(info["CHANNEL"])) return; if (info["NAME"]) { if (info["NAME"] == Mud_name()) return ; rhost = DNS_MASTER->query_mud_info(info["NAME"]); if (!rhost || !DNS_MASTER->dns_mudp(info["NAME"])) { // We don't accept the message. But ping them anyway. PING_Q->send_ping_q(info["HOSTADDRESS"], info["PORTUDP"]); return ; } if (info["HOSTADDRESS"] != rhost["HOSTADDRESS"]) { // Faked. sheeze... dns_log("dns_fake",sprintf( "Gchannel: %s %s\n%s", ctime(time()), info["HOSTADDRESS"],info["MYINFO"])); DNS_MASTER->send_udp(info["HOSTADDRESS"], info["PORTUDP"], "@@@"+DNS_WARNING+ "||NAME:"+Mud_name()+ "||MSG: Fake remote_q msg: "+info["CHANNEL"]+ "||FAKEHOST:"+info["HOSTADDRESS"]+ "@@@\n"); return; } ob=find_player(info["TARGET_ID"]); if(!userp(ob)) return; if( ob->is_ghost() || ob->query("env/invisibility") > 0 ) return; DNS_MASTER->send_udp(rhost["HOSTADDRESS"], rhost["PORTUDP"], "@@@" + "remote_a" + "||NAME:" + Mud_name() + "||PORTUDP:" + udp_port() + "||CHANNEL:" + info["CHANNEL"] + "||SOURCE_ID:" + info["SOURCE_ID"] + "||MSG:" + info["MSG"] + "||TARGET:" + sprintf("mud=%s name=%s id=%s age=%d gender=%s respect=%s rude=%s ", Mud_name(),ob->query("name"),ob->query("id"),ob->query("age"),ob->query("gender"), RANK_D->query_respect(ob),RANK_D->query_rude(ob) ) + "@@@\n"); } }
void send_locate_q(string who) { mapping info; string *muds; int i; i = sizeof(muds = keys(info=(mapping)DNS_MASTER->query_muds())); while(i--) { if(lower_case(muds[i]) == lower_case(Mud_name())) continue; DNS_MASTER->send_udp(info[muds[i]]["HOSTADDRESS"], info[muds[i]]["PORTUDP"], "@@@"+DNS_LOCATE_Q+ "||NAME:"+Mud_name()+ "||PORTUDP:"+ udp_port() + "||TARGET:"+lower_case(who)+ "||ASKWIZ:"+(string)this_player()->query("name")+ "@@@\n"); } return; }
// This is the interface to the intermud channels void send_msg(string channel, string id, string name, string msg, int emoted) { string *names; int i; mapping muds; mapping svcs; mapping minfo; if( !this_player() // Prevent from being called by ourself. || !ACCESS_CHECK(previous_object())) return; #ifdef DEBUG set("channel_id", "网际巫师频道精灵"); CHANNEL_D->do_channel(this_object(), "sys", "prepare to send gwizmsg"); #endif muds = (mapping)DNS_MASTER->query_muds(); svcs = (mapping)DNS_MASTER->query_svc(); msg = replace_string(msg, "|", ""); msg = replace_string(msg, "@@@", ""); // use keys(svcs) because none of the muds not in svcs can possibley // receive the message names = keys(svcs); i = sizeof(names); while(i--) if (names[i] != mud_nname()) { minfo = muds[names[i]]; if(!mapp(minfo) || !mapp(svcs[names[i]]) || !(svcs[names[i]]["gwizmsg"] & SVC_UDP)) continue; DNS_MASTER->send_udp(minfo["HOSTADDRESS"], minfo["PORTUDP"], "@@@" + DNS_GWIZMSG + "||NAME:" + Mud_name() + "||PORTUDP:" + udp_port() + "||WIZNAME:" + capitalize(id) + "||CNAME:" + name + "||GWIZ:" + msg + "||CHANNEL:" + channel + (emoted?"||EMOTE:1":"") + "@@@\n"); } }
/* return non zero if error */ static int udp_open(URLContext *h, const char *uri, int flags) { char hostname[1024], localaddr[1024] = ""; int port, udp_fd = -1, tmp, bind_ret = -1; UDPContext *s = h->priv_data; int is_output; const char *p; char buf[256]; struct sockaddr_storage my_addr; socklen_t len; int reuse_specified = 0; int i, num_include_sources = 0, num_exclude_sources = 0; char *include_sources[32], *exclude_sources[32]; h->is_streamed = 1; h->max_packet_size = 1472; is_output = !(flags & AVIO_FLAG_READ); s->ttl = 16; s->buffer_size = is_output ? UDP_TX_BUF_SIZE : UDP_MAX_PKT_SIZE; p = strchr(uri, '?'); if (p) { if (av_find_info_tag(buf, sizeof(buf), "reuse", p)) { char *endptr = NULL; s->reuse_socket = strtol(buf, &endptr, 10); /* assume if no digits were found it is a request to enable it */ if (buf == endptr) s->reuse_socket = 1; reuse_specified = 1; } if (av_find_info_tag(buf, sizeof(buf), "ttl", p)) { s->ttl = strtol(buf, NULL, 10); } if (av_find_info_tag(buf, sizeof(buf), "localport", p)) { s->local_port = strtol(buf, NULL, 10); } if (av_find_info_tag(buf, sizeof(buf), "pkt_size", p)) { h->max_packet_size = strtol(buf, NULL, 10); } if (av_find_info_tag(buf, sizeof(buf), "buffer_size", p)) { s->buffer_size = strtol(buf, NULL, 10); } if (av_find_info_tag(buf, sizeof(buf), "connect", p)) { s->is_connected = strtol(buf, NULL, 10); } if (av_find_info_tag(buf, sizeof(buf), "localaddr", p)) { av_strlcpy(localaddr, buf, sizeof(localaddr)); } if (av_find_info_tag(buf, sizeof(buf), "sources", p)) { if (parse_source_list(buf, include_sources, &num_include_sources, FF_ARRAY_ELEMS(include_sources))) goto fail; } if (av_find_info_tag(buf, sizeof(buf), "block", p)) { if (parse_source_list(buf, exclude_sources, &num_exclude_sources, FF_ARRAY_ELEMS(exclude_sources))) goto fail; } } /* fill the dest addr */ av_url_split(NULL, 0, NULL, 0, hostname, sizeof(hostname), &port, NULL, 0, uri); /* XXX: fix av_url_split */ if (hostname[0] == '\0' || hostname[0] == '?') { /* only accepts null hostname if input */ if (!(flags & AVIO_FLAG_READ)) goto fail; } else { if (ff_udp_set_remote_url(h, uri) < 0) goto fail; } if ((s->is_multicast || !s->local_port) && (h->flags & AVIO_FLAG_READ)) s->local_port = port; udp_fd = udp_socket_create(s, &my_addr, &len, localaddr); if (udp_fd < 0) goto fail; /* Follow the requested reuse option, unless it's multicast in which * case enable reuse unless explicitly disabled. */ if (s->reuse_socket || (s->is_multicast && !reuse_specified)) { s->reuse_socket = 1; if (setsockopt (udp_fd, SOL_SOCKET, SO_REUSEADDR, &(s->reuse_socket), sizeof(s->reuse_socket)) != 0) goto fail; } /* If multicast, try binding the multicast address first, to avoid * receiving UDP packets from other sources aimed at the same UDP * port. This fails on windows. This makes sending to the same address * using sendto() fail, so only do it if we're opened in read-only mode. */ if (s->is_multicast && !(h->flags & AVIO_FLAG_WRITE)) { bind_ret = bind(udp_fd,(struct sockaddr *)&s->dest_addr, len); } /* bind to the local address if not multicast or if the multicast * bind failed */ /* the bind is needed to give a port to the socket now */ if (bind_ret < 0 && bind(udp_fd,(struct sockaddr *)&my_addr, len) < 0) { log_net_error(h, AV_LOG_ERROR, "bind failed"); goto fail; } len = sizeof(my_addr); getsockname(udp_fd, (struct sockaddr *)&my_addr, &len); s->local_port = udp_port(&my_addr, len); if (s->is_multicast) { if (h->flags & AVIO_FLAG_WRITE) { /* output */ if (udp_set_multicast_ttl(udp_fd, s->ttl, (struct sockaddr *)&s->dest_addr) < 0) goto fail; } if (h->flags & AVIO_FLAG_READ) { /* input */ if (num_include_sources && num_exclude_sources) { av_log(h, AV_LOG_ERROR, "Simultaneously including and excluding multicast sources is not supported\n"); goto fail; } if (num_include_sources) { if (udp_set_multicast_sources(udp_fd, (struct sockaddr *)&s->dest_addr, s->dest_addr_len, include_sources, num_include_sources, 1) < 0) goto fail; } else { if (udp_join_multicast_group(udp_fd, (struct sockaddr *)&s->dest_addr) < 0) goto fail; } if (num_exclude_sources) { if (udp_set_multicast_sources(udp_fd, (struct sockaddr *)&s->dest_addr, s->dest_addr_len, exclude_sources, num_exclude_sources, 0) < 0) goto fail; } } } if (is_output) { /* limit the tx buf size to limit latency */ tmp = s->buffer_size; if (setsockopt(udp_fd, SOL_SOCKET, SO_SNDBUF, &tmp, sizeof(tmp)) < 0) { log_net_error(h, AV_LOG_ERROR, "setsockopt(SO_SNDBUF)"); goto fail; } } else { /* set udp recv buffer size to the largest possible udp packet size to * avoid losing data on OSes that set this too low by default. */ tmp = s->buffer_size; if (setsockopt(udp_fd, SOL_SOCKET, SO_RCVBUF, &tmp, sizeof(tmp)) < 0) { log_net_error(h, AV_LOG_WARNING, "setsockopt(SO_RECVBUF)"); } /* make the socket non-blocking */ ff_socket_nonblock(udp_fd, 1); } if (s->is_connected) { if (connect(udp_fd, (struct sockaddr *) &s->dest_addr, s->dest_addr_len)) { log_net_error(h, AV_LOG_ERROR, "connect"); goto fail; } } for (i = 0; i < num_include_sources; i++) av_freep(&include_sources[i]); for (i = 0; i < num_exclude_sources; i++) av_freep(&exclude_sources[i]); s->udp_fd = udp_fd; return 0; fail: if (udp_fd >= 0) closesocket(udp_fd); for (i = 0; i < num_include_sources; i++) av_freep(&include_sources[i]); for (i = 0; i < num_exclude_sources; i++) av_freep(&exclude_sources[i]); return AVERROR(EIO); }
/* return non zero if error */ static int udp_open(URLContext *h, const char *uri, int flags) { char hostname[1024]; int port, udp_fd = -1, tmp, bind_ret = -1; UDPContext *s = NULL; int is_output; const char *p; char buf[256]; #if !CONFIG_IPV6 struct sockaddr_in my_addr; #else struct sockaddr_storage my_addr; #endif int len; h->is_streamed = 1; h->max_packet_size = 1472; is_output = (flags & URL_WRONLY); if(!ff_network_init()) return AVERROR(EIO); s = av_mallocz(sizeof(UDPContext)); if (!s) return AVERROR(ENOMEM); h->priv_data = s; s->ttl = 16; s->buffer_size = is_output ? UDP_TX_BUF_SIZE : UDP_MAX_PKT_SIZE; p = strchr(uri, '?'); if (p) { s->reuse_socket = find_info_tag(buf, sizeof(buf), "reuse", p); if (find_info_tag(buf, sizeof(buf), "ttl", p)) { s->ttl = strtol(buf, NULL, 10); } if (find_info_tag(buf, sizeof(buf), "localport", p)) { s->local_port = strtol(buf, NULL, 10); } if (find_info_tag(buf, sizeof(buf), "pkt_size", p)) { h->max_packet_size = strtol(buf, NULL, 10); } if (find_info_tag(buf, sizeof(buf), "buffer_size", p)) { s->buffer_size = strtol(buf, NULL, 10); } } /* fill the dest addr */ url_split(NULL, 0, NULL, 0, hostname, sizeof(hostname), &port, NULL, 0, uri); /* XXX: fix url_split */ if (hostname[0] == '\0' || hostname[0] == '?') { /* only accepts null hostname if input */ if (flags & URL_WRONLY) goto fail; } else { udp_set_remote_url(h, uri); } if (s->is_multicast && !(h->flags & URL_WRONLY)) s->local_port = port; udp_fd = udp_socket_create(s, &my_addr, &len); if (udp_fd < 0) goto fail; if (s->reuse_socket) if (setsockopt (udp_fd, SOL_SOCKET, SO_REUSEADDR, &(s->reuse_socket), sizeof(s->reuse_socket)) != 0) goto fail; /* the bind is needed to give a port to the socket now */ /* if multicast, try the multicast address bind first */ if (s->is_multicast && !(h->flags & URL_WRONLY)) { bind_ret = bind(udp_fd,(struct sockaddr *)&s->dest_addr, len); } /* bind to the local address if not multicast or if the multicast * bind failed */ if (bind_ret < 0 && bind(udp_fd,(struct sockaddr *)&my_addr, len) < 0) goto fail; len = sizeof(my_addr); getsockname(udp_fd, (struct sockaddr *)&my_addr, &len); s->local_port = udp_port(&my_addr, len); if (s->is_multicast) { if (h->flags & URL_WRONLY) { /* output */ if (udp_set_multicast_ttl(udp_fd, s->ttl, (struct sockaddr *)&s->dest_addr) < 0) goto fail; } else { /* input */ if (udp_join_multicast_group(udp_fd, (struct sockaddr *)&s->dest_addr) < 0) goto fail; } } if (is_output) { /* limit the tx buf size to limit latency */ tmp = s->buffer_size; if (setsockopt(udp_fd, SOL_SOCKET, SO_SNDBUF, &tmp, sizeof(tmp)) < 0) { av_log(NULL, AV_LOG_ERROR, "setsockopt(SO_SNDBUF): %s\n", strerror(errno)); goto fail; } } else { /* set udp recv buffer size to the largest possible udp packet size to * avoid losing data on OSes that set this too low by default. */ tmp = s->buffer_size; if (setsockopt(udp_fd, SOL_SOCKET, SO_RCVBUF, &tmp, sizeof(tmp)) < 0) { av_log(NULL, AV_LOG_WARNING, "setsockopt(SO_RECVBUF): %s\n", strerror(errno)); } /* make the socket non-blocking */ ff_socket_nonblock(udp_fd, 1); } s->udp_fd = udp_fd; return 0; fail: if (udp_fd >= 0) closesocket(udp_fd); av_free(s); return AVERROR(EIO); }
/* return non zero if error */ static int udp_open(URLContext *h, const char *uri, int flags) { char hostname[1024]; int port, udp_fd = -1, tmp, bind_ret = -1; UDPContext *s = NULL; int is_output; const char *p; char buf[256]; struct sockaddr_storage my_addr; int len; int reuse_specified = 0; h->is_streamed = 1; h->max_packet_size = 1472; is_output = !(flags & AVIO_FLAG_READ); s = av_mallocz(sizeof(UDPContext)); if (!s) return AVERROR(ENOMEM); h->priv_data = s; s->ttl = 16; s->buffer_size = is_output ? UDP_TX_BUF_SIZE : UDP_MAX_PKT_SIZE; s->circular_buffer_size = 7*188*4096; p = strchr(uri, '?'); if (p) { if (av_find_info_tag(buf, sizeof(buf), "reuse", p)) { char *endptr=NULL; s->reuse_socket = strtol(buf, &endptr, 10); /* assume if no digits were found it is a request to enable it */ if (buf == endptr) s->reuse_socket = 1; reuse_specified = 1; } if (av_find_info_tag(buf, sizeof(buf), "ttl", p)) { s->ttl = strtol(buf, NULL, 10); } if (av_find_info_tag(buf, sizeof(buf), "localport", p)) { s->local_port = strtol(buf, NULL, 10); } if (av_find_info_tag(buf, sizeof(buf), "pkt_size", p)) { h->max_packet_size = strtol(buf, NULL, 10); } if (av_find_info_tag(buf, sizeof(buf), "buffer_size", p)) { s->buffer_size = strtol(buf, NULL, 10); } if (av_find_info_tag(buf, sizeof(buf), "connect", p)) { s->is_connected = strtol(buf, NULL, 10); } if (av_find_info_tag(buf, sizeof(buf), "buf_size", p)) { s->circular_buffer_size = strtol(buf, NULL, 10)*188; } } /* fill the dest addr */ av_url_split(NULL, 0, NULL, 0, hostname, sizeof(hostname), &port, NULL, 0, uri); /* XXX: fix av_url_split */ if (hostname[0] == '\0' || hostname[0] == '?') { /* only accepts null hostname if input */ if (!(flags & AVIO_FLAG_READ)) goto fail; } else { if (ff_udp_set_remote_url(h, uri) < 0) goto fail; } if (s->is_multicast && (h->flags & AVIO_FLAG_READ)) s->local_port = port; udp_fd = udp_socket_create(s, &my_addr, &len); if (udp_fd < 0) goto fail; /* Follow the requested reuse option, unless it's multicast in which * case enable reuse unless explicitely disabled. */ if (s->reuse_socket || (s->is_multicast && !reuse_specified)) { s->reuse_socket = 1; if (setsockopt (udp_fd, SOL_SOCKET, SO_REUSEADDR, &(s->reuse_socket), sizeof(s->reuse_socket)) != 0) goto fail; } /* the bind is needed to give a port to the socket now */ /* if multicast, try the multicast address bind first */ if (s->is_multicast && (h->flags & AVIO_FLAG_READ)) { bind_ret = bind(udp_fd,(struct sockaddr *)&s->dest_addr, len); } /* bind to the local address if not multicast or if the multicast * bind failed */ if (bind_ret < 0 && bind(udp_fd,(struct sockaddr *)&my_addr, len) < 0) goto fail; len = sizeof(my_addr); getsockname(udp_fd, (struct sockaddr *)&my_addr, &len); s->local_port = udp_port(&my_addr, len); if (s->is_multicast) { if (!(h->flags & AVIO_FLAG_READ)) { /* output */ if (udp_set_multicast_ttl(udp_fd, s->ttl, (struct sockaddr *)&s->dest_addr) < 0) goto fail; } else { /* input */ if (udp_join_multicast_group(udp_fd, (struct sockaddr *)&s->dest_addr) < 0) goto fail; } } if (is_output) { /* limit the tx buf size to limit latency */ tmp = s->buffer_size; if (setsockopt(udp_fd, SOL_SOCKET, SO_SNDBUF, &tmp, sizeof(tmp)) < 0) { av_log(h, AV_LOG_ERROR, "setsockopt(SO_SNDBUF): %s\n", strerror(errno)); goto fail; } } else { /* set udp recv buffer size to the largest possible udp packet size to * avoid losing data on OSes that set this too low by default. */ tmp = s->buffer_size; if (setsockopt(udp_fd, SOL_SOCKET, SO_RCVBUF, &tmp, sizeof(tmp)) < 0) { av_log(h, AV_LOG_WARNING, "setsockopt(SO_RECVBUF): %s\n", strerror(errno)); } /* make the socket non-blocking */ ff_socket_nonblock(udp_fd, 1); } if (s->is_connected) { if (connect(udp_fd, (struct sockaddr *) &s->dest_addr, s->dest_addr_len)) { av_log(h, AV_LOG_ERROR, "connect: %s\n", strerror(errno)); goto fail; } } s->udp_fd = udp_fd; #if 0 && HAVE_PTHREADS if (!is_output && s->circular_buffer_size) { /* start the task going */ s->fifo = av_fifo_alloc(s->circular_buffer_size); if (pthread_create(&s->circular_buffer_thread, NULL, circular_buffer_task, h)) { av_log(h, AV_LOG_ERROR, "pthread_create failed\n"); goto fail; } } #endif return 0; fail: if (udp_fd >= 0) closesocket(udp_fd); av_fifo_free(s->fifo); av_free(s); return AVERROR(EIO); }
/* return non zero if error */ static int udp_open(URLContext *h, const char *uri, int flags) { char hostname[1024], localaddr[1024] = ""; int port, udp_fd = -1, tmp, bind_ret = -1, dscp = -1; UDPContext *s = h->priv_data; int is_output; const char *p; char buf[256]; struct sockaddr_storage my_addr; socklen_t len; int i, num_include_sources = 0, num_exclude_sources = 0; char *include_sources[32], *exclude_sources[32]; h->is_streamed = 1; is_output = !(flags & AVIO_FLAG_READ); if (s->buffer_size < 0) s->buffer_size = is_output ? UDP_TX_BUF_SIZE : UDP_MAX_PKT_SIZE; if (s->sources) { if (parse_source_list(s->sources, include_sources, &num_include_sources, FF_ARRAY_ELEMS(include_sources))) goto fail; } if (s->block) { if (parse_source_list(s->block, exclude_sources, &num_exclude_sources, FF_ARRAY_ELEMS(exclude_sources))) goto fail; } if (s->pkt_size > 0) h->max_packet_size = s->pkt_size; p = strchr(uri, '?'); if (p) { if (av_find_info_tag(buf, sizeof(buf), "reuse", p)) { char *endptr = NULL; s->reuse_socket = strtol(buf, &endptr, 10); /* assume if no digits were found it is a request to enable it */ if (buf == endptr) s->reuse_socket = 1; } if (av_find_info_tag(buf, sizeof(buf), "overrun_nonfatal", p)) { char *endptr = NULL; s->overrun_nonfatal = strtol(buf, &endptr, 10); /* assume if no digits were found it is a request to enable it */ if (buf == endptr) s->overrun_nonfatal = 1; if (!HAVE_PTHREAD_CANCEL) av_log(h, AV_LOG_WARNING, "'overrun_nonfatal' option was set but it is not supported " "on this build (pthread support is required)\n"); } if (av_find_info_tag(buf, sizeof(buf), "ttl", p)) { s->ttl = strtol(buf, NULL, 10); } if (av_find_info_tag(buf, sizeof(buf), "udplite_coverage", p)) { s->udplite_coverage = strtol(buf, NULL, 10); } if (av_find_info_tag(buf, sizeof(buf), "localport", p)) { s->local_port = strtol(buf, NULL, 10); } if (av_find_info_tag(buf, sizeof(buf), "pkt_size", p)) { s->pkt_size = strtol(buf, NULL, 10); } if (av_find_info_tag(buf, sizeof(buf), "buffer_size", p)) { s->buffer_size = strtol(buf, NULL, 10); } if (av_find_info_tag(buf, sizeof(buf), "connect", p)) { s->is_connected = strtol(buf, NULL, 10); } if (av_find_info_tag(buf, sizeof(buf), "dscp", p)) { dscp = strtol(buf, NULL, 10); } if (av_find_info_tag(buf, sizeof(buf), "fifo_size", p)) { s->circular_buffer_size = strtol(buf, NULL, 10); if (!HAVE_PTHREAD_CANCEL) av_log(h, AV_LOG_WARNING, "'circular_buffer_size' option was set but it is not supported " "on this build (pthread support is required)\n"); } if (av_find_info_tag(buf, sizeof(buf), "localaddr", p)) { av_strlcpy(localaddr, buf, sizeof(localaddr)); } if (av_find_info_tag(buf, sizeof(buf), "sources", p)) { if (parse_source_list(buf, include_sources, &num_include_sources, FF_ARRAY_ELEMS(include_sources))) goto fail; } if (av_find_info_tag(buf, sizeof(buf), "block", p)) { if (parse_source_list(buf, exclude_sources, &num_exclude_sources, FF_ARRAY_ELEMS(exclude_sources))) goto fail; } if (!is_output && av_find_info_tag(buf, sizeof(buf), "timeout", p)) s->timeout = strtol(buf, NULL, 10); if (is_output && av_find_info_tag(buf, sizeof(buf), "broadcast", p)) s->is_broadcast = strtol(buf, NULL, 10); } /* handling needed to support options picking from both AVOption and URL */ s->circular_buffer_size *= 188; if (flags & AVIO_FLAG_WRITE) { h->max_packet_size = s->pkt_size; } else { h->max_packet_size = UDP_MAX_PKT_SIZE; } h->rw_timeout = s->timeout; /* fill the dest addr */ av_url_split(NULL, 0, NULL, 0, hostname, sizeof(hostname), &port, NULL, 0, uri); /* XXX: fix av_url_split */ if (hostname[0] == '\0' || hostname[0] == '?') { /* only accepts null hostname if input */ if (!(flags & AVIO_FLAG_READ)) goto fail; } else { if (ff_udp_set_remote_url(h, uri) < 0) goto fail; } if ((s->is_multicast || s->local_port <= 0) && (h->flags & AVIO_FLAG_READ)) s->local_port = port; if (localaddr[0]) udp_fd = udp_socket_create(s, &my_addr, &len, localaddr); else udp_fd = udp_socket_create(s, &my_addr, &len, s->localaddr); if (udp_fd < 0) goto fail; s->local_addr_storage=my_addr; //store for future multicast join /* Follow the requested reuse option, unless it's multicast in which * case enable reuse unless explicitly disabled. */ if (s->reuse_socket > 0 || (s->is_multicast && s->reuse_socket < 0)) { s->reuse_socket = 1; if (setsockopt (udp_fd, SOL_SOCKET, SO_REUSEADDR, &(s->reuse_socket), sizeof(s->reuse_socket)) != 0) goto fail; } if (s->is_broadcast) { #ifdef SO_BROADCAST if (setsockopt (udp_fd, SOL_SOCKET, SO_BROADCAST, &(s->is_broadcast), sizeof(s->is_broadcast)) != 0) #endif goto fail; } /* Set the checksum coverage for UDP-Lite (RFC 3828) for sending and receiving. * The receiver coverage has to be less than or equal to the sender coverage. * Otherwise, the receiver will drop all packets. */ if (s->udplite_coverage) { if (setsockopt (udp_fd, IPPROTO_UDPLITE, UDPLITE_SEND_CSCOV, &(s->udplite_coverage), sizeof(s->udplite_coverage)) != 0) av_log(h, AV_LOG_WARNING, "socket option UDPLITE_SEND_CSCOV not available"); if (setsockopt (udp_fd, IPPROTO_UDPLITE, UDPLITE_RECV_CSCOV, &(s->udplite_coverage), sizeof(s->udplite_coverage)) != 0) av_log(h, AV_LOG_WARNING, "socket option UDPLITE_RECV_CSCOV not available"); } if (dscp >= 0) { dscp <<= 2; if (setsockopt (udp_fd, IPPROTO_IP, IP_TOS, &dscp, sizeof(dscp)) != 0) goto fail; } /* If multicast, try binding the multicast address first, to avoid * receiving UDP packets from other sources aimed at the same UDP * port. This fails on windows. This makes sending to the same address * using sendto() fail, so only do it if we're opened in read-only mode. */ if (s->is_multicast && !(h->flags & AVIO_FLAG_WRITE)) { bind_ret = bind(udp_fd,(struct sockaddr *)&s->dest_addr, len); } /* bind to the local address if not multicast or if the multicast * bind failed */ /* the bind is needed to give a port to the socket now */ if (bind_ret < 0 && bind(udp_fd,(struct sockaddr *)&my_addr, len) < 0) { log_net_error(h, AV_LOG_ERROR, "bind failed"); goto fail; } len = sizeof(my_addr); getsockname(udp_fd, (struct sockaddr *)&my_addr, &len); s->local_port = udp_port(&my_addr, len); if (s->is_multicast) { if (h->flags & AVIO_FLAG_WRITE) { /* output */ if (udp_set_multicast_ttl(udp_fd, s->ttl, (struct sockaddr *)&s->dest_addr) < 0) goto fail; } if (h->flags & AVIO_FLAG_READ) { /* input */ if (num_include_sources && num_exclude_sources) { av_log(h, AV_LOG_ERROR, "Simultaneously including and excluding multicast sources is not supported\n"); goto fail; } if (num_include_sources) { if (udp_set_multicast_sources(udp_fd, (struct sockaddr *)&s->dest_addr, s->dest_addr_len, include_sources, num_include_sources, 1) < 0) goto fail; } else { if (udp_join_multicast_group(udp_fd, (struct sockaddr *)&s->dest_addr,(struct sockaddr *)&s->local_addr_storage) < 0) goto fail; } if (num_exclude_sources) { if (udp_set_multicast_sources(udp_fd, (struct sockaddr *)&s->dest_addr, s->dest_addr_len, exclude_sources, num_exclude_sources, 0) < 0) goto fail; } } } if (is_output) { /* limit the tx buf size to limit latency */ tmp = s->buffer_size; if (setsockopt(udp_fd, SOL_SOCKET, SO_SNDBUF, &tmp, sizeof(tmp)) < 0) { log_net_error(h, AV_LOG_ERROR, "setsockopt(SO_SNDBUF)"); goto fail; } } else { /* set udp recv buffer size to the requested value (default 64K) */ tmp = s->buffer_size; if (setsockopt(udp_fd, SOL_SOCKET, SO_RCVBUF, &tmp, sizeof(tmp)) < 0) { log_net_error(h, AV_LOG_WARNING, "setsockopt(SO_RECVBUF)"); } len = sizeof(tmp); if (getsockopt(udp_fd, SOL_SOCKET, SO_RCVBUF, &tmp, &len) < 0) { log_net_error(h, AV_LOG_WARNING, "getsockopt(SO_RCVBUF)"); } else { av_log(h, AV_LOG_DEBUG, "end receive buffer size reported is %d\n", tmp); if(tmp < s->buffer_size) av_log(h, AV_LOG_WARNING, "attempted to set receive buffer to size %d but it only ended up set as %d", s->buffer_size, tmp); } /* make the socket non-blocking */ ff_socket_nonblock(udp_fd, 1); } if (s->is_connected) { if (connect(udp_fd, (struct sockaddr *) &s->dest_addr, s->dest_addr_len)) { log_net_error(h, AV_LOG_ERROR, "connect"); goto fail; } } for (i = 0; i < num_include_sources; i++) av_freep(&include_sources[i]); for (i = 0; i < num_exclude_sources; i++) av_freep(&exclude_sources[i]); s->udp_fd = udp_fd; #if HAVE_PTHREAD_CANCEL if (!is_output && s->circular_buffer_size) { int ret; /* start the task going */ s->fifo = av_fifo_alloc(s->circular_buffer_size); ret = pthread_mutex_init(&s->mutex, NULL); if (ret != 0) { av_log(h, AV_LOG_ERROR, "pthread_mutex_init failed : %s\n", strerror(ret)); goto fail; } ret = pthread_cond_init(&s->cond, NULL); if (ret != 0) { av_log(h, AV_LOG_ERROR, "pthread_cond_init failed : %s\n", strerror(ret)); goto cond_fail; } ret = pthread_create(&s->circular_buffer_thread, NULL, circular_buffer_task, h); if (ret != 0) { av_log(h, AV_LOG_ERROR, "pthread_create failed : %s\n", strerror(ret)); goto thread_fail; } s->thread_started = 1; } #endif return 0; #if HAVE_PTHREAD_CANCEL thread_fail: pthread_cond_destroy(&s->cond); cond_fail: pthread_mutex_destroy(&s->mutex); #endif fail: if (udp_fd >= 0) closesocket(udp_fd); av_fifo_freep(&s->fifo); for (i = 0; i < num_include_sources; i++) av_freep(&include_sources[i]); for (i = 0; i < num_exclude_sources; i++) av_freep(&exclude_sources[i]); return AVERROR(EIO); }
int udp_open( hnd_t *p_handle, obe_udp_opts_t *udp_opts ) { int udp_fd = -1, tmp, bind_ret = -1; struct sockaddr_storage my_addr; int len; obe_udp_ctx *s = calloc( 1, sizeof(*s) ); *p_handle = NULL; if( !s ) return -1; strncpy( s->hostname, udp_opts->hostname, sizeof(s->hostname) ); s->port = udp_opts->port; s->local_port = udp_opts->local_port; s->reuse_socket = udp_opts->reuse_socket; s->ttl = udp_opts->ttl; s->buffer_size = udp_opts->buffer_size; s->miface = udp_opts->miface; if( udp_set_remote_url( s ) < 0 ) goto fail; udp_fd = udp_socket_create( s, &my_addr, &len ); if( udp_fd < 0 ) goto fail; if( s->reuse_socket || s->is_multicast ) { s->reuse_socket = 1; if( setsockopt( udp_fd, SOL_SOCKET, SO_REUSEADDR, &(s->reuse_socket), sizeof(s->reuse_socket) ) != 0) goto fail; } /* bind to the local address if not multicast or if the multicast * bind failed */ if( bind_ret < 0 && bind( udp_fd, (struct sockaddr *)&my_addr, len ) < 0 ) goto fail; len = sizeof(my_addr); getsockname( udp_fd, (struct sockaddr *)&my_addr, (socklen_t *) &len ); s->local_port = udp_port( &my_addr, len ); /* set output multicast ttl */ if( s->is_multicast && udp_set_multicast_opts( udp_fd, s ) < 0 ) goto fail; /* limit the tx buf size to limit latency */ tmp = s->buffer_size; if( setsockopt( udp_fd, SOL_SOCKET, SO_SNDBUF, &tmp, sizeof(tmp) ) < 0 ) goto fail; if( s->is_connected && connect( udp_fd, (struct sockaddr *)&s->dest_addr, s->dest_addr_len ) ) goto fail; s->udp_fd = udp_fd; *p_handle = s; return 0; fail: if( udp_fd >= 0 ) close( udp_fd ); free( s ); return -1; }