| /****************************************************************************** |
| *(C) Copyright 2011 Marvell International Ltd. |
| * All Rights Reserved |
| ******************************************************************************/ |
| /*-------------------------------------------------------------------------------------------------------------------- |
| * ------------------------------------------------------------------------------------------------------------------- |
| * |
| * Filename: tcp_api.c |
| * |
| * Description: The APIs to handle TCP operations. |
| * |
| * History: |
| * Aug, 13 2012 - Haili Wang(hlw@marvell.com) Creation of file |
| * |
| * Notes: |
| * |
| ******************************************************************************/ |
| |
| #include <sys/types.h> |
| #include <sys/socket.h> |
| #include <sys/ioctl.h> |
| #include <net/if.h> |
| #include <unistd.h> |
| #include <stdlib.h> |
| #include <fcntl.h> |
| #include <errno.h> |
| #include <termios.h> |
| #include <arpa/inet.h> |
| #include "diag_config.h" |
| #include "diag_al.h" |
| #include "diag_comm.h" |
| #include "linux_types.h" |
| #include "utlEventHandler.h" |
| #include "pxa_dbg.h" |
| |
| #include "diag_api.h" |
| #include "server_api.h" |
| #include "tcp_state_machine.h" |
| |
| |
| static int tcpfd = -1; |
| static int sockfd = -1; |
| |
| static utlEventHandlerId_T tcpHandler; |
| static utlEventHandlerId_T acceptedHandler; |
| static DIAG_COM_RX_Packet_Info RxPacket; |
| |
| int ifc_init(void); |
| int ifc_init(void) { return 0;} |
| void ifc_close(void); |
| void ifc_close(void) {} |
| int ifc_up(const char *name); |
| int ifc_up(const char *name __attribute__ ((unused))) { return 0; } |
| int ifc_set_addr(const char *name, unsigned addr); |
| int ifc_set_addr(const char *name __attribute__ ((unused)), unsigned addr __attribute__ ((unused))) { return 0; } |
| int ifc_set_mask(const char *name, unsigned mask); |
| int ifc_set_mask(const char *name __attribute__ ((unused)), unsigned mask __attribute__ ((unused))) { return 0; } |
| |
| static utlReturnCode_T ReceiveDataFromTCP(const utlEventHandlerType_T handler_type UNUSED, |
| const utlEventHandlerType_T event_type UNUSED, |
| const int fd, |
| const utlRelativeTime_P2c period_p UNUSED, |
| void *arg_p UNUSED) |
| { |
| int dwBytesTransferred, offset; |
| UINT8* transferBuffer = RxPacket.buffer; |
| |
| //try to receive a complete packet if buffer is large enough to hold it |
| offset = RxPacket.total_bytes_expected > ICAT_DATA_LENGTH ? 0 : RxPacket.total_bytes_received; |
| if ((dwBytesTransferred = read(fd, transferBuffer + offset, ICAT_DATA_LENGTH - offset)) > 0) |
| { |
| |
| DBGMSG("----DIAG received from TCP:%d, len:%d\n", fd, dwBytesTransferred); |
| handleDataFromACAT(&RxPacket, dwBytesTransferred); |
| return utlSUCCESS; |
| } |
| |
| else if(dwBytesTransferred == 0) |
| { |
| DBGMSG("***** TCP Connection closed by peer *****\r\n"); |
| TCPDisconnect(); |
| return utlSUCCESS; |
| } |
| |
| else |
| { |
| if(errno == ECONNRESET) |
| { |
| DBGMSG("***** TCP Connection reset by peer *****\r\n"); |
| TCPDisconnect(); |
| return utlSUCCESS; |
| } |
| ERRMSG("***** TCP Read failed:%d,%s. *****\r\n", dwBytesTransferred,strerror(errno)); |
| return utlFAILED; |
| } |
| } |
| |
| |
| int createListenSocket(void) |
| { |
| int addr_reuse = 1; |
| F_ENTER(); |
| while(sockfd < 0) |
| { |
| sockfd = socket(AF_INET, SOCK_STREAM, 0); |
| if(sockfd < 0) |
| { |
| ERRMSG("create tcp socket error:%s\n", strerror(errno)); |
| } |
| } |
| if(setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &addr_reuse, sizeof(addr_reuse)) < 0) |
| { |
| ERRMSG("setsockopt : %s", strerror(errno)); |
| } |
| F_LEAVE(); |
| return sockfd; |
| } |
| |
| int configInterface(void) |
| { |
| // ifconfig rndis0 192.168.1.101 netmask 255.255.255.0 up |
| in_addr_t addr, netmask; |
| |
| if(diagConfig.network_settings.is_local) |
| return 0; |
| |
| addr = inet_addr(diagConfig.network_settings.diag_ip); |
| netmask = inet_addr(diagConfig.network_settings.diag_netmask); |
| |
| ifc_init(); |
| if(ifc_up(diagConfig.network_settings.net_dev)) |
| { |
| ERRMSG("failed to turn on interface"); |
| ifc_close(); |
| return -1; |
| } |
| if(ifc_set_addr(diagConfig.network_settings.net_dev, addr)) |
| { |
| ERRMSG("failed to set ipaddr"); |
| ifc_close(); |
| return -1; |
| } |
| |
| if(ifc_set_mask(diagConfig.network_settings.net_dev, netmask)) |
| { |
| ERRMSG("failed to set netmask"); |
| ifc_close(); |
| return -1; |
| } |
| |
| ifc_close(); |
| return 0; |
| } |
| |
| |
| |
| static int acceptTCPSocket(void) |
| { |
| struct sockaddr_in peer_addr; |
| int addr_size = 0; |
| int ret; |
| int flags; |
| |
| ret = accept(sockfd, (struct sockaddr *)&peer_addr, (socklen_t*)&addr_size); |
| if( ret < 0) |
| { |
| ERRMSG("accept tcp socket on %s:%d error:%s\n", diagConfig.network_settings.diag_ip, diagConfig.network_settings.port,strerror(errno)); |
| } |
| else |
| { |
| DBGMSG("client %s:%d is accepted!\n", inet_ntoa(peer_addr.sin_addr), ntohs(peer_addr.sin_port)); |
| tcpfd = ret; |
| RxPacket.total_bytes_expected = 0; |
| RxPacket.total_bytes_received = 0; |
| RxPacket.buffer = malloc(ICAT_DATA_LENGTH); |
| tcpHandler = utlSetFdEventHandler(utlEVENT_HANDLER_TYPE_READ, utlEVENT_HANDLER_PRIORITY_MEDIUM, tcpfd, ReceiveDataFromTCP, NULL); |
| /* Since blocking write behavior is preferred, |
| * undo O_NONBLOCK flag set in utlSetFdEventHandler |
| */ |
| if ((flags = fcntl(tcpfd, F_GETFL)) != -1) |
| { |
| flags &= ~O_NONBLOCK; |
| if(fcntl(tcpfd, F_SETFL, flags) == -1) |
| { |
| ERRMSG("F_SETFL error: %s", strerror(errno)); |
| } |
| } |
| else |
| { |
| ERRMSG("F_GETFL error: %s", strerror(errno)); |
| } |
| } |
| return ret; |
| } |
| |
| static utlReturnCode_T AcceptClient(const utlEventHandlerType_T handler_type UNUSED, |
| const utlEventHandlerType_T event_type UNUSED, |
| const int fd UNUSED, |
| const utlRelativeTime_P2c period_p UNUSED, |
| void *arg_p UNUSED) |
| { |
| if (acceptTCPSocket() < 0) |
| { |
| return utlFAILED; |
| } |
| else |
| { |
| TCPAccept(); |
| return utlSUCCESS; |
| } |
| } |
| |
| int prepareListenSocket(void) |
| { |
| struct sockaddr_in serv_addr; |
| int ret; |
| |
| memset(&serv_addr,0,sizeof(serv_addr)); |
| serv_addr.sin_family = AF_INET; |
| serv_addr.sin_port = htons(diagConfig.network_settings.port); |
| serv_addr.sin_addr.s_addr = inet_addr(diagConfig.network_settings.diag_ip); |
| |
| ret = bind(sockfd,(const struct sockaddr*)&serv_addr,sizeof(serv_addr)); |
| if(ret < 0) |
| { |
| ERRMSG("bind tcp socket on %s:%d error:%s\n", diagConfig.network_settings.diag_ip, diagConfig.network_settings.port,strerror(errno)); |
| } |
| else |
| { |
| ret = listen(sockfd, 1); |
| if(ret < 0) |
| { |
| ERRMSG("listen to tcp socket on %s:%d error:%s\n", diagConfig.network_settings.diag_ip, diagConfig.network_settings.port,strerror(errno)); |
| } |
| else |
| { |
| acceptedHandler = utlSetFdEventHandler(utlEVENT_HANDLER_TYPE_READ, utlEVENT_HANDLER_PRIORITY_MEDIUM, sockfd, AcceptClient, NULL); |
| } |
| } |
| return ret; |
| } |
| |
| |
| void closeListenSocket(void) |
| { |
| F_ENTER(); |
| utlDeleteEventHandler(acceptedHandler); |
| close(sockfd); |
| sockfd = -1; |
| } |
| |
| void closeDataSocket(void) |
| { |
| F_ENTER(); |
| utlDeleteEventHandler(tcpHandler); |
| close(tcpfd); |
| tcpfd = -1; |
| free(RxPacket.buffer); |
| } |
| |
| int SendTCPdata(const unsigned char * data, unsigned len) |
| { |
| if(tcpfd > 0) |
| { |
| ssize_t count = len; |
| int ret, retry = 5; |
| while (count > 0) |
| { |
| ret = send(tcpfd, data, count, MSG_NOSIGNAL); |
| if (ret == count) |
| { |
| count = 0; |
| break; /* send all bytes successfully */ |
| } |
| else if (ret >= 0) |
| { |
| data += ret; |
| count -= ret; |
| if(--retry == 0) |
| { |
| ERRMSG("tcp send incomplete: %d of %d bytes sent\n", len - count, len); |
| break; |
| } |
| continue; |
| } |
| else if (ret < 0) |
| { |
| ERRMSG("tcp send error: %s\n", strerror(errno)); |
| return -1; |
| } |
| } |
| return len - count; |
| } |
| else |
| return -1; |
| } |
| |
| void InitTCP(void) |
| { |
| F_ENTER(); |
| InitTCPMachine(); |
| F_LEAVE(); |
| } |
| |
| static int IsNetIfUp(void) |
| { |
| struct ifreq ifr; |
| int s, err; |
| |
| if ((s = socket( AF_INET, SOCK_DGRAM, 0)) < 0) |
| { |
| err = errno; |
| ERRMSG("%s:socket error:%s", __func__, strerror(err)); |
| return -1; |
| } |
| ifr.ifr_name[0] = '\0'; |
| strncat(ifr.ifr_name, diagConfig.network_settings.net_dev, IFNAMSIZ - 1); |
| if (ioctl(s, SIOCGIFFLAGS, &ifr) < 0) |
| { |
| err = errno; |
| ERRMSG("%s:%s", __func__, strerror(err)); |
| close(s); |
| return -1; |
| } |
| close(s); |
| s = ifr.ifr_flags & IFF_UP ? 1 : 0; |
| DBGMSG("net interface %s is %s", diagConfig.network_settings.net_dev, s ? "up" : "down"); |
| return s; |
| } |
| |
| void handleTCPUevent(int status) |
| { |
| if(!diagConfig.network_settings.is_local && status == 0) //remove |
| { |
| if(IsNetIfUp() == 0) |
| { |
| TCPDisconnect(); |
| } |
| } |
| } |