#include #include #include #include #include #include #include #include #include #include #include "ldp_struct.h" #include "ldp_linux.h" #include "ldp_socket_impl.h" fd_set _global_write_set; fd_set _global_read_set; uint32_t _global_high_fd = 0; struct ldp_socket_linux **_global_socket_array = NULL; uint32_t _globale_socket_array_size; extern struct ldp_if_linux_list* _global_if_list; int console_socket = 0; ldp_bool ldp_socket_mgr_handle_verify(ldp_socket_mgr_handle handle) { return LDP_TRUE; } ldp_bool ldp_socket_handle_verify(ldp_socket_mgr_handle handle,ldp_socket_handle socket){ return LDP_TRUE; } void _sockaddr2ldp_dest(const struct sockaddr* addr,ldp_dest* dest) { dest->addr.protocol = AF_INET; /* addr->sa_family; */ switch(dest->addr.protocol) { case AF_INET: dest->port = ntohs(((struct sockaddr_in*)addr)->sin_port); dest->addr.u.ipv4 = ntohl(((struct sockaddr_in*)addr)->sin_addr.s_addr); break; default: assert(0); } } void _ldp_dest2sockaddr(const ldp_dest* dest,struct sockaddr* addr) { memset(addr,0,sizeof(struct sockaddr)); addr->sa_family = dest->addr.protocol; switch(dest->addr.protocol) { case AF_INET: ((struct sockaddr_in*)addr)->sin_port = htons(dest->port); ((struct sockaddr_in*)addr)->sin_addr.s_addr = htonl(dest->addr.u.ipv4); break; default: assert(0); } } void _ldp_if2inaddr(int fd,const ldp_if* iff,struct in_addr* in) { struct ifreq ifr; strcpy(ifr.ifr_name,iff->name); ifr.ifr_ifindex = iff->index; if(ioctl(fd,SIOCGIFADDR,&ifr) < 0) { perror("IFADDR"); return; } switch(ifr.ifr_addr.sa_family) { case AF_INET: in->s_addr = ((struct sockaddr_in*)(&ifr.ifr_addr))->sin_addr.s_addr; break; default: assert(0); } } ldp_socket_mgr_handle ldp_socket_mgr_open(ldp_instance_handle user_data) { FD_ZERO(&_global_write_set); FD_ZERO(&_global_read_set); _global_high_fd = 0; _global_socket_array = (ldp_socket_linux**)malloc(1024 * sizeof(ldp_socket_linux*)); memset(_global_socket_array,0,1024 * sizeof(ldp_socket_linux*)); _globale_socket_array_size = 1024; return 0; } void ldp_socket_mgr_close(ldp_socket_mgr_handle handle) { FD_ZERO(&_global_write_set); FD_ZERO(&_global_read_set); _global_high_fd = 0; free(_global_socket_array); _global_socket_array = NULL; } void ldp_socket_close(ldp_socket_mgr_handle handle,ldp_socket_handle socket) { ldp_socket_readlist_del(handle,socket); ldp_socket_writelist_del(handle,socket); close(socket); } ldp_socket_handle ldp_socket_create_tcp(ldp_socket_mgr_handle handle) { int fd = socket(AF_INET,SOCK_STREAM,0); if (fd > 0) return fd; return 0; } ldp_socket_handle ldp_socket_create_udp(ldp_socket_mgr_handle handle) { int fd = socket(AF_INET,SOCK_DGRAM,0); if (fd > 0) return fd; return 0; } ldp_socket_handle ldp_socket_tcp_accept(ldp_socket_mgr_handle handle,ldp_socket_handle socket,ldp_dest* from) { struct sockaddr *addr = (struct sockaddr*)malloc(sizeof(struct sockaddr)); int size = sizeof(struct sockaddr); int in; if(addr == NULL) return 0; if((in = accept(socket,addr,&size)) < 0) return 0; _sockaddr2ldp_dest(addr,from); free(addr); return (uint32_t)in; } ldp_return_enum ldp_socket_bind(ldp_socket_mgr_handle handle,ldp_socket_handle socket,const ldp_dest* local) { struct sockaddr addr; _ldp_dest2sockaddr(local,&addr); if(bind(socket,&addr,sizeof(struct sockaddr_in)) < 0) return LDP_FAILURE; return LDP_SUCCESS; } ldp_return_enum ldp_socket_tcp_listen(ldp_socket_mgr_handle handle,ldp_socket_handle socket,int depth) { if(listen(socket,depth) < 0) return LDP_FAILURE; return LDP_SUCCESS; } ldp_return_enum ldp_socket_tcp_connect(ldp_socket_mgr_handle handle,ldp_socket_handle socket,const ldp_dest* to) { struct sockaddr addr,*iaddr = NULL; if(to != NULL) { _ldp_dest2sockaddr(to,&addr); iaddr = &addr; } else { iaddr = NULL; } if(connect(socket,iaddr,sizeof(struct sockaddr))<0) { if(errno == EINPROGRESS) return LDP_NON_BLOCKING; if(errno == EALREADY) return LDP_SUCCESS; perror("connect"); return LDP_FAILURE; } return LDP_SUCCESS; } ldp_return_enum ldp_socket_connect_status(ldp_socket_mgr_handle handle, ldp_socket_handle socket) { int size = sizeof(int); int num = 0; if(getsockopt(socket,SOL_SOCKET,SO_ERROR,&num,&size) < 0 || num != 0) { return LDP_FAILURE; } return LDP_SUCCESS; } int ldp_socket_get_errno(const ldp_socket_mgr_handle handle, ldp_socket_handle socket) { return errno; } ldp_return_enum ldp_socket_options(ldp_socket_mgr_handle handle,ldp_socket_handle socket,uint32_t flag) { int one = 1; if(flag & LDP_SOCKET_REUSE) { if(setsockopt(socket,SOL_SOCKET,SO_REUSEADDR,(char*)&one,sizeof(one)) < 0) { return LDP_FAILURE; } } if(flag & LDP_SOCKET_NONBLOCK) { if(fcntl(socket,F_SETFL,O_NONBLOCK) < 0) { return LDP_FAILURE; } } return LDP_SUCCESS; } ldp_return_enum ldp_socket_multicast_options(ldp_socket_mgr_handle handle,ldp_socket_handle socket,int ttl,int loop) { int zero = loop; int one = ttl; if(setsockopt(socket,IPPROTO_IP,IP_MULTICAST_TTL,&one,sizeof(one)) < 0) return LDP_FAILURE; if(setsockopt(socket,IPPROTO_IP,IP_MULTICAST_LOOP,&zero,sizeof(zero)) < 0) return LDP_FAILURE; return LDP_SUCCESS; } ldp_return_enum ldp_socket_multicast_if_tx(ldp_socket_mgr_handle handle,ldp_socket_handle socket,const ldp_if* iff) { struct in_addr in; if(iff == NULL) { in.s_addr = ntohl(INADDR_ANY); } else { _ldp_if2inaddr(socket,iff,&in); } if(setsockopt(socket,IPPROTO_IP,IP_MULTICAST_IF,&in, sizeof(struct in_addr)) < 0) { return LDP_FAILURE; } return LDP_SUCCESS; } ldp_return_enum ldp_socket_multicast_if_join(ldp_socket_mgr_handle handle,ldp_socket_handle socket,const ldp_if* iff,const ldp_inet_addr *mult) { struct ip_mreq mreq; int fd = socket; _ldp_if2inaddr(fd,iff,&mreq.imr_interface); mreq.imr_multiaddr.s_addr = htonl(mult->u.ipv4); if(setsockopt(fd,IPPROTO_IP,IP_ADD_MEMBERSHIP,&mreq,sizeof(struct ip_mreq))<0) return LDP_FAILURE; return LDP_SUCCESS; } void ldp_socket_multicast_if_drop(ldp_socket_mgr_handle handle,ldp_socket_handle socket,const ldp_if* iff,const ldp_inet_addr *mult) { struct ip_mreq mreq; int fd = socket; _ldp_if2inaddr(fd,iff,&mreq.imr_interface); mreq.imr_multiaddr.s_addr = htonl(mult->u.ipv4); setsockopt(fd,IPPROTO_IP,IP_DROP_MEMBERSHIP,&mreq,sizeof(struct ip_mreq)); } ldp_return_enum ldp_socket_readlist_add(ldp_socket_mgr_handle handle,ldp_socket_handle socket,void* extra,ldp_socket_enum type) { ldp_socket_linux *lsl = (ldp_socket_linux*)malloc(sizeof(ldp_socket_linux)); if(lsl) { lsl->extra = extra; lsl->type = type; lsl->socket = socket; assert(_global_socket_array[socket] == NULL); _global_socket_array[socket] = lsl; FD_SET(socket,&_global_read_set); if(socket > _global_high_fd) _global_high_fd = socket; } return LDP_SUCCESS; } void ldp_socket_readlist_del(ldp_socket_mgr_handle handle,ldp_socket_handle socket) { if(socket > 0) { FD_CLR(socket,&_global_read_set); if(_global_socket_array[socket] != NULL) { free(_global_socket_array[socket]); _global_socket_array[socket] = NULL; } } } ldp_return_enum ldp_socket_writelist_add(ldp_socket_mgr_handle handle,ldp_socket_handle socket,void* extra,ldp_socket_enum type) { ldp_socket_linux *lsl = (ldp_socket_linux*)malloc(sizeof(ldp_socket_linux)); if(socket > 0 && lsl) { lsl->extra = extra; lsl->type = type; lsl->socket = socket; assert(_global_socket_array[socket] == NULL); _global_socket_array[socket] = lsl; FD_SET(socket,&_global_write_set); if(socket > _global_high_fd) _global_high_fd = socket; return LDP_SUCCESS; } return LDP_FAILURE; } void ldp_socket_writelist_del(ldp_socket_mgr_handle handle,ldp_socket_handle socket) { if(socket > 0) { FD_CLR(socket,&_global_write_set); if(_global_socket_array[socket] != NULL) { free(_global_socket_array[socket]); _global_socket_array[socket] = NULL; } } } int ldp_socket_tcp_read(ldp_socket_mgr_handle handle,ldp_socket_handle socket,uint8_t* buffer,int size) { return read(socket,buffer,size); } int ldp_socket_tcp_write(ldp_socket_mgr_handle handle,ldp_socket_handle socket,uint8_t* buffer,int size) { int retval = 0; retval = write(socket,buffer,size); return retval; } int ldp_socket_udp_sendto(ldp_socket_mgr_handle handle,ldp_socket_handle socket,uint8_t* buffer,int size, const ldp_dest *to) { struct sockaddr addr; _ldp_dest2sockaddr(to,&addr); return sendto(socket,buffer,size,0,&addr,sizeof(struct sockaddr)); } int ldp_socket_udp_recvfrom(ldp_socket_mgr_handle handle,ldp_socket_handle socket,uint8_t* buffer,int size, ldp_dest *from) { struct sockaddr *addr = (struct sockaddr*)malloc(sizeof(struct sockaddr)); ldp_if_linux *iff = NULL; int len = 0, retval = 0; len = sizeof(struct sockaddr); retval = recvfrom(socket,buffer,size,0,addr,&len); if(retval < 0) { perror("recvfrom"); return 0; } _sockaddr2ldp_dest(addr,from); iff = LDP_LIST_HEAD(_global_if_list); while(iff != NULL) { if(iff->flags & IFF_POINTOPOINT) { if(((struct sockaddr_in*)addr)->sin_addr.s_addr == iff->dstaddr) { from->if_handle = iff->handle; break; } } else { if((((struct sockaddr_in*)addr)->sin_addr.s_addr & iff->netmask) == (iff->addr & iff->netmask)) { from->if_handle = iff->handle; break; } } iff = LDP_LIST_NEXT(_global_if_list,iff,_if); } if(addr) free(addr); return retval; }