├── LICENSE ├── Makefile ├── README.md ├── example ├── Makefile ├── example.c └── test.h264 ├── include ├── h264.h ├── net.h ├── rtp.h ├── rtsp.h ├── rtsp_handler.h └── rtsp_parse.h └── src ├── Makefile ├── h264.c ├── rtp.c ├── rtsp_handler.c ├── rtsp_parse.c ├── tcp.c └── udp.c /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 cijliu 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | all: 2 | @cd src && $(MAKE) all 3 | @cd example && $(MAKE) all 4 | 5 | clean: 6 | @cd example && $(MAKE) clean 7 | @cd src && $(MAKE) clean 8 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # librtsp 2 | RTSP协议库 3 | 4 | 5 | 6 | * 编译 7 | 8 | > make 9 | 10 | * 运行 11 | > cd example && ./demo 12 | > 13 | > **rtsp服务默认端口设置为8554,客户端需要指定端口,比如服务器IP:192.168.1.2, 那么RTSP地址为:rtsp://192.168.1.2:8554/live,测试程序会循环推送H264文件内容** 14 | 15 | -------------------------------------------------------------------------------- /example/Makefile: -------------------------------------------------------------------------------- 1 | PRO_NAME = demo 2 | PRO_ROOT = $(shell pwd)/.. 3 | CC = $(CROSS_COMPILE)gcc 4 | INC := -I$(PRO_ROOT) 5 | CFLAGS += $(INC) 6 | LIB = -lpthread -lrt -L$(SRC_DIR) -lrtsp 7 | SRC_DIR := $(PRO_ROOT)/src 8 | 9 | SRC = \ 10 | example.c 11 | 12 | all: 13 | $(CC) $(CFLAGS) -o $(PRO_NAME) $(SRC) $(LIB_SRC) $(LIB) 14 | 15 | clean: 16 | @rm demo -rf 17 | -------------------------------------------------------------------------------- /example/example.c: -------------------------------------------------------------------------------- 1 | /* 2 | * @Author: cijliu 3 | * @Date: 2021-02-04 16:04:16 4 | * @LastEditTime: 2021-02-26 17:01:59 5 | */ 6 | #include 7 | #include "include/rtp.h" 8 | #include "include/rtsp_parse.h" 9 | #include "include/rtsp_handler.h" 10 | #include "include/h264.h" 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include "pthread.h" 17 | #include "include/net.h" 18 | #define H264_FILENAME "test.h264" 19 | #define SOCKET_ERROR (-1) 20 | #define INVALID_SOCKET (-1) 21 | #define BUF_SIZE 2048 22 | typedef struct { 23 | unsigned char *data; 24 | int len; 25 | } file_t; 26 | pthread_t rtp; 27 | int g_pause = 0; 28 | ip_t ip; 29 | const char* rfc822_datetime_format(time_t time, char* datetime) 30 | { 31 | int r; 32 | char *date = asctime(gmtime(&time)); 33 | char mon[8], week[8]; 34 | int year, day, hour, min, sec; 35 | sscanf(date, "%s %s %d %d:%d:%d %d",week, mon, &day, &hour, &min, &sec, &year); 36 | r = snprintf(datetime, 32, "%s, %02d %s %04d %02d:%02d:%02d GMT", 37 | week,day,mon,year,hour,min,sec); 38 | return r > 0 && r < 32 ? datetime : NULL; 39 | } 40 | uint32_t rtsp_get_reltime (void) 41 | { 42 | struct timespec tp; 43 | uint64_t ts; 44 | clock_gettime(CLOCK_MONOTONIC, &tp); 45 | ts = (tp.tv_sec * 1000000+ tp.tv_nsec / 1000); 46 | //printf("usec:%d\n",ts); 47 | return ts; 48 | } 49 | 50 | int open_h264_file(char *filename, file_t * file) 51 | { 52 | struct stat info; 53 | stat(filename, &info); 54 | FILE *fp=fopen(filename, "rb"); 55 | file->data = (unsigned char *)malloc(info.st_size); 56 | memset(file->data, 0, info.st_size); 57 | fread(file->data, 1, info.st_size, fp); 58 | file->len = info.st_size; 59 | fclose(fp); 60 | return 0; 61 | } 62 | void close_h264_file(file_t *file) 63 | { 64 | if(file->data){ 65 | free(file->data); 66 | file->data = NULL; 67 | } 68 | 69 | } 70 | 71 | void *rtp_thread(void *args) 72 | { 73 | ip_t* ipaddr = &ip; 74 | udp_t udp,rtcp; 75 | if(udp_server_init(&udp, 45504)){ 76 | printf("udp server init fail.\n"); 77 | return NULL; 78 | } 79 | if(udp_server_init(&rtcp, 45505)){ 80 | printf("udp server init fail.\n"); 81 | return NULL; 82 | } 83 | char *filename = H264_FILENAME; 84 | file_t file; 85 | uint32_t rtptime = 0; 86 | int idr = 0; 87 | rtp_header_t header; 88 | rtp_header_init(&header); 89 | header.seq = 0; 90 | header.ts = 0; 91 | open_h264_file(filename, &file); 92 | h264_nalu_t *nalu = h264_nal_packet_malloc(file.data, file.len); 93 | printf("rtp server init.\n"); 94 | while(g_pause){ 95 | h264_nalu_t *h264_nal = nalu; 96 | while(h264_nal && g_pause){ 97 | if(h264_nal->type == H264_NAL_IDR || h264_nal->type == H264_NAL_PFRAME){ 98 | if(rtptime == 0){ 99 | rtptime = rtsp_get_reltime(); 100 | } 101 | else { 102 | while((rtptime + 40000) > rtsp_get_reltime()){ 103 | usleep(100); 104 | } 105 | //printf("sleep:%d us\n", rtsp_get_reltime() - rtptime); 106 | rtptime = rtsp_get_reltime(); 107 | 108 | } 109 | idr = 1; 110 | rtp_packet_t* rtp_ptk = rtp_packet_malloc(&header, h264_nal->data, h264_nal->len); 111 | rtp_packet_t* cur = rtp_ptk; 112 | while(cur){ 113 | udp_server_send_msg(&udp, ipaddr->ip, ipaddr->port, (unsigned char*)cur->data, cur->len); 114 | cur = cur->next; 115 | } 116 | rtp_packet_free(rtp_ptk); 117 | } 118 | else if((h264_nal->type == H264_NAL_SPS || h264_nal->type == H264_NAL_PPS) && !idr){ 119 | rtp_packet_t* cur = rtp_packet_malloc(&header, h264_nal->data, h264_nal->len); 120 | udp_server_send_msg(&udp, ipaddr->ip, ipaddr->port, (unsigned char*)cur->data, cur->len); 121 | rtp_packet_free(cur); 122 | } 123 | h264_nal = h264_nal->next; 124 | } 125 | } 126 | h264_nal_packet_free(nalu); 127 | close_h264_file(&file); 128 | udp_server_deinit(&udp); 129 | udp_server_deinit(&rtcp); 130 | printf("rtp exit\n"); 131 | } 132 | extern const char* rfc822_datetime_format(time_t time, char* datetime); 133 | void* rtsp_thread(void *args) 134 | { 135 | ip_t * ipaddr = (ip_t *)args; 136 | tcp_t tcp; 137 | int client = 0; 138 | if(tcp_server_init(&tcp, 8554)){ 139 | printf("tcp server init fail.\n"); 140 | return NULL; 141 | } 142 | 143 | char msg[2048]; 144 | char sdp[2048]="v=0\n" 145 | "o=- 16409863082207520751 16409863082207520751 IN IP4 0.0.0.0\n" 146 | "c=IN IP4 0.0.0.0\n" 147 | "t=0 0\n" 148 | "a=range:npt=0-1.4\n" 149 | "a=recvonly\n" 150 | "m=video 0 RTP/AVP 97\n" 151 | "a=rtpmap:97 H264/90000\n" 152 | ; 153 | while(1){ 154 | if(client == 0){ 155 | fd_set fds; 156 | struct timeval tv; 157 | int r; 158 | 159 | FD_ZERO(&fds); 160 | FD_SET(tcp.sock,&fds); 161 | tv.tv_sec = 2; 162 | tv.tv_usec = 0; 163 | r = select(tcp.sock + 1,&fds,NULL,NULL,&tv); 164 | if(-1 == r || 0 == r) 165 | { 166 | continue; 167 | } 168 | client = tcp_server_wait_client(&tcp); 169 | sprintf(ipaddr->ip, "%s", inet_ntoa(tcp.addr.sin_addr) ); 170 | ipaddr->port = ntohs(tcp.addr.sin_port); 171 | printf("rtsp client ip:%s port:%d\n", inet_ntoa(tcp.addr.sin_addr), ntohs(tcp.addr.sin_port)); 172 | } 173 | char recvbuffer[2048]; 174 | tcp_server_receive_msg(&tcp, client, recvbuffer, sizeof(recvbuffer)); 175 | rtsp_msg_t rtsp = rtsp_msg_load(recvbuffer); 176 | char datetime[30]; 177 | rfc822_datetime_format(time(NULL), datetime); 178 | rtsp_rely_t rely = get_rely(rtsp); 179 | memcpy(rely.datetime, datetime, strlen(datetime)); 180 | switch(rtsp.request.method){ 181 | case SETUP: 182 | rely.tansport.server_port=45504; 183 | rtsp_rely_dumps(rely, msg, 2048); 184 | sprintf(ip.ip, "%s", ipaddr->ip); 185 | ip.port = rtsp.tansport.client_port; 186 | g_pause = 1; 187 | pthread_create(&rtp,NULL,rtp_thread,&ip); 188 | printf("rtp client ip:%s port:%d\n",ip.ip, ip.port); 189 | break; 190 | case DESCRIBE: 191 | rely.sdp_len = strlen(sdp); 192 | memcpy(rely.sdp, sdp, rely.sdp_len); 193 | rtsp_rely_dumps(rely, msg, 2048); 194 | break; 195 | case TEARDOWN: 196 | rtsp_rely_dumps(rely, msg, 2048); 197 | tcp_server_send_msg(&tcp, client, msg, strlen(msg)); 198 | tcp_server_close_client(&tcp, client); 199 | client = 0; 200 | g_pause = 0; 201 | continue; 202 | default: 203 | rtsp_rely_dumps(rely, msg, 2048); 204 | break; 205 | } 206 | tcp_server_send_msg(&tcp, client, msg, strlen(msg)); 207 | usleep(1000); 208 | } 209 | tcp_server_deinit(&tcp); 210 | } 211 | 212 | void main() 213 | { 214 | pthread_t rtsp_id; 215 | pthread_create(&rtsp_id,NULL,rtsp_thread,&ip); 216 | while(1){ 217 | sleep(1); 218 | } 219 | 220 | } 221 | -------------------------------------------------------------------------------- /example/test.h264: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cijliu/librtsp/2ec1a81ad65280568a0c7c16420d7c10fde13b04/example/test.h264 -------------------------------------------------------------------------------- /include/h264.h: -------------------------------------------------------------------------------- 1 | /* 2 | * @Author: cijliu 3 | * @Date: 2021-02-08 19:51:36 4 | * @LastEditTime: 2021-02-26 13:55:05 5 | */ 6 | #ifndef __H264_H__ 7 | #define __H264_H__ 8 | #include "stdint.h" 9 | #include "stdio.h" 10 | #include "include/rtp.h" 11 | #define H264_NAL(v) (v & 0x1F) 12 | typedef enum { 13 | H264_NAL_PFRAME = 1, 14 | H264_NAL_IDR = 5, 15 | H264_NAL_SEI = 6, 16 | H264_NAL_SPS = 7, 17 | H264_NAL_PPS = 8 18 | } h264_nalu_enum_t; 19 | typedef struct h264_nalu{ 20 | h264_nalu_enum_t type; 21 | uint8_t *data; 22 | uint32_t len; 23 | struct h264_nalu *next; 24 | } h264_nalu_t; 25 | 26 | uint8_t* h264_nalu_find(uint8_t* ptr, uint8_t* end); 27 | uint8_t* h264_search_start_code(uint8_t* ptr, uint8_t* end); 28 | int h264_nal_type(unsigned char* ptr); 29 | int h264_nal_new_access(unsigned char* ptr, uint8_t* end); 30 | rtp_packet_t* rtp_h264_packet_malloc(rtp_header_t *header, uint8_t *data, uint32_t len); 31 | 32 | h264_nalu_t *h264_nal_packet_malloc(unsigned char *buf, int len); 33 | void h264_nal_packet_free(h264_nalu_t *nal); 34 | #endif -------------------------------------------------------------------------------- /include/net.h: -------------------------------------------------------------------------------- 1 | /* 2 | * @Author: cijliu 3 | * @Date: 2021-02-11 17:01:24 4 | * @LastEditTime: 2021-02-23 17:50:10 5 | */ 6 | #ifndef __NET_H__ 7 | #define __NET_H__ 8 | #include "stdio.h" 9 | #include "string.h" 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include "errno.h" 15 | #include 16 | #define TCP_MAX_CLIENT 128 17 | typedef struct { 18 | char ip[16]; 19 | int port; 20 | } ip_t; 21 | typedef struct { 22 | int sock; 23 | int port; 24 | struct sockaddr_in addr; 25 | int client[TCP_MAX_CLIENT]; 26 | } tcp_t; 27 | 28 | typedef struct { 29 | int sock; 30 | int port; 31 | struct sockaddr_in addr; 32 | } udp_t; 33 | int tcp_server_init(tcp_t *tcp, int port); 34 | int tcp_server_wait_client(tcp_t *tcp); 35 | int tcp_server_close_client(tcp_t *tcp, int client); 36 | int tcp_server_send_msg(tcp_t *tcp, int client, unsigned char *data, int len); 37 | int tcp_server_receive_msg(tcp_t *tcp, int client, unsigned char *data, int len); 38 | int tcp_server_deinit(tcp_t *tcp); 39 | 40 | int udp_server_init(udp_t *udp, int port); 41 | int udp_server_send_msg(udp_t *udp, const char *ip, const int port, unsigned char *data, int len); 42 | int udp_server_recive_msg(udp_t *udp, ip_t *ip, unsigned char *data, int len); 43 | int udp_server_deinit(udp_t *udp); 44 | #endif -------------------------------------------------------------------------------- /include/rtp.h: -------------------------------------------------------------------------------- 1 | /* 2 | * @Author: cijliu 3 | * @Date: 2021-02-04 16:29:39 4 | * @LastEditTime: 2021-02-26 16:38:24 5 | */ 6 | #ifndef __RTP_H__ 7 | #define __RTP_H__ 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #define __RTP_BIG_ENDIAN (1) 15 | #define __RTP_LITTLE_ENDIAN (0) 16 | #define __RTP_ENDIAN_MODE __RTP_LITTLE_ENDIAN 17 | #define RTP_MAX_PAYLOAD (1280) 18 | #define RTP_RBSP_MAX_LEN (RTP_MAX_PAYLOAD-14) 19 | #define RTP_ASSERT(x) do{assert(x != NULL);}while(0) 20 | typedef enum { 21 | RTP_H264 = 97, 22 | } rtp_pt_enum_t; 23 | typedef struct { 24 | #if __RTP_ENDIAN_MODE == __RTP_BIG_ENDIAN 25 | uint16_t v:2; 26 | uint16_t p:1; 27 | uint16_t x:1; 28 | uint16_t cc:4; 29 | uint16_t m:1; 30 | uint16_t pt:7; 31 | #else 32 | uint16_t cc:4; 33 | uint16_t x:1; 34 | uint16_t p:1; 35 | uint16_t v:2; 36 | uint16_t pt:7; 37 | uint16_t m:1; 38 | #endif 39 | uint16_t seq; 40 | uint32_t ts; 41 | uint32_t ssrc; 42 | } rtp_header_t; 43 | typedef struct rtp_packet{ 44 | union { 45 | uint8_t data[RTP_MAX_PAYLOAD]; 46 | struct { 47 | rtp_header_t hdr; 48 | uint8_t fu_indicator; 49 | uint8_t fu_header; 50 | uint8_t rbsp[RTP_RBSP_MAX_LEN]; 51 | } nalu; 52 | }; 53 | struct rtp_packet *next; 54 | uint64_t len; 55 | }rtp_packet_t; 56 | 57 | void rtp_header_init(rtp_header_t *header); 58 | rtp_packet_t* rtp_packet_malloc(rtp_header_t *header, uint8_t *data, uint32_t len); 59 | void rtp_packet_free(rtp_packet_t *pkt); 60 | #endif -------------------------------------------------------------------------------- /include/rtsp.h: -------------------------------------------------------------------------------- 1 | /* 2 | * @Author: cijliu 3 | * @Date: 2021-02-04 16:43:10 4 | * @LastEditTime: 2021-02-20 16:39:00 5 | */ 6 | #ifndef __RTSP_H__ 7 | #define __RTSP_H__ 8 | #include 9 | #include 10 | #include 11 | #include 12 | #define DEFAULT_STRING_MIN_LEN (32) 13 | #define DEFAULT_STRING_MAX_LEN (256) 14 | #define DEFAULT_RTSP_PORT (554) 15 | #define DEFAULT_RTSP_SUPPORT_METHOD "DESCRIBE,SETUP,TEARDOWN,PLAY,PAUSE,ANNOUNCE,RECORD,GET_PARAMETER,SET_PARAMETER" 16 | typedef enum { 17 | OPTIONS = 0, 18 | DESCRIBE, 19 | SETUP, 20 | PLAY, 21 | RECORD, 22 | PAUSE, 23 | TEARDOWN, 24 | ANNOUNCE, 25 | SET_PARAMETER, 26 | GET_PARAMETER, 27 | REDIRECT, 28 | BUTT, 29 | } rtsp_method_enum_t; 30 | 31 | typedef struct { 32 | char prefix[DEFAULT_STRING_MIN_LEN]; 33 | char ip[DEFAULT_STRING_MIN_LEN]; 34 | uint32_t port; 35 | char uri[DEFAULT_STRING_MAX_LEN]; 36 | } rtsp_url_t; 37 | 38 | typedef struct { 39 | rtsp_method_enum_t method; 40 | rtsp_url_t url; 41 | } rtsp_request_t; 42 | 43 | typedef struct { 44 | uint8_t is_tcp; 45 | uint8_t is_multicast; 46 | union 47 | { 48 | uint32_t rtp_port; 49 | uint32_t client_port; 50 | }; 51 | union 52 | { 53 | uint32_t rtcp_port; 54 | uint32_t server_port; 55 | }; 56 | 57 | 58 | } rtsp_transport_t; 59 | typedef struct { 60 | uint32_t status; 61 | uint32_t cseq; 62 | char session[DEFAULT_STRING_MIN_LEN]; 63 | char desc[DEFAULT_STRING_MIN_LEN]; 64 | char datetime[DEFAULT_STRING_MIN_LEN]; 65 | char sdp[1024]; 66 | uint32_t timeout; 67 | uint32_t rtp_seq; 68 | uint64_t rtptime; 69 | union { 70 | uint32_t is_sdp; 71 | uint32_t sdp_len; 72 | }; 73 | 74 | rtsp_transport_t tansport; 75 | rtsp_request_t request; 76 | } rtsp_rely_t; 77 | 78 | typedef struct { 79 | rtsp_request_t request; 80 | uint32_t cseq; 81 | rtsp_transport_t tansport; 82 | #ifdef __RTSP_USER_AGENT 83 | char ua[DEFAULT_STRING_MAX_LEN]; 84 | #endif 85 | #ifdef __RTSP_RANGE 86 | char range[DEFAULT_STRING_MAX_LEN]; 87 | #endif 88 | #ifdef __RTSP_ACCEPT 89 | char accept[DEFAULT_STRING_MAX_LEN]; 90 | #endif 91 | char session[DEFAULT_STRING_MIN_LEN]; 92 | } rtsp_msg_t; 93 | 94 | 95 | 96 | #endif -------------------------------------------------------------------------------- /include/rtsp_handler.h: -------------------------------------------------------------------------------- 1 | /* 2 | * @Author: cijliu 3 | * @Date: 2021-02-05 15:12:06 4 | * @LastEditTime: 2021-02-20 14:28:43 5 | */ 6 | #ifndef __RTSP_HANDLER_H__ 7 | #define __RTSP_HANDLER_H__ 8 | #include "rtsp.h" 9 | void rtsp_options_handler(rtsp_msg_t rtsp); 10 | void rtsp_describe_handler(rtsp_msg_t rtsp); 11 | void rtsp_setup_handler(rtsp_msg_t rtsp); 12 | void rtsp_play_handler(rtsp_msg_t rtsp); 13 | void rtsp_record_handler(rtsp_msg_t rtsp); 14 | void rtsp_pause_handler(rtsp_msg_t rtsp); 15 | void rtsp_teardown_handler(rtsp_msg_t rtsp); 16 | void rtsp_announce_handler(rtsp_msg_t rtsp); 17 | void rtsp_set_parameter_handler(rtsp_msg_t rtsp); 18 | void rtsp_get_parameter_handler(rtsp_msg_t rtsp); 19 | void rtsp_redirect_handler(rtsp_msg_t rtsp); 20 | 21 | rtsp_msg_t rtsp_msg_load(const char *msg); 22 | rtsp_rely_t get_rely(rtsp_msg_t rtsp); 23 | int rtsp_rely_dumps(rtsp_rely_t rely, char *msg, uint32_t len); 24 | #endif -------------------------------------------------------------------------------- /include/rtsp_parse.h: -------------------------------------------------------------------------------- 1 | /* 2 | * @Author: cijliu 3 | * @Date: 2021-02-05 14:32:30 4 | * @LastEditTime: 2021-02-26 16:38:36 5 | */ 6 | #ifndef __RTSP_PARSE_H__ 7 | #define __RTSP_PARSE_H__ 8 | #include "rtsp.h" 9 | int rtsp_parse_msg(const char *msg, rtsp_msg_t *rtsp); 10 | #endif 11 | -------------------------------------------------------------------------------- /src/Makefile: -------------------------------------------------------------------------------- 1 | PRO_NAME = librtsp.a 2 | PRO_ROOT = $(shell pwd) 3 | CC = $(CROSS_COMPILE)gcc 4 | AR = $(CROSS_COMPILE)ar 5 | INC := -I$(PRO_ROOT)/.. 6 | CFLAGS += $(INC) 7 | LIB = -lpthread -lrt 8 | SRC_DIR := $(PRO_ROOT) 9 | LIB_SRC = \ 10 | $(SRC_DIR)/rtsp_parse.c \ 11 | $(SRC_DIR)/rtsp_handler.c \ 12 | $(SRC_DIR)/rtp.c \ 13 | $(SRC_DIR)/h264.c \ 14 | $(SRC_DIR)/tcp.c \ 15 | $(SRC_DIR)/udp.c \ 16 | 17 | obj = $(LIB_SRC:%.c=%.o) 18 | 19 | 20 | all:$(obj) 21 | $(AR) -rcs $(PRO_NAME) $(obj) 22 | clean: 23 | @rm $(obj) $(PRO_NAME) -rf 24 | -------------------------------------------------------------------------------- /src/h264.c: -------------------------------------------------------------------------------- 1 | /* 2 | * @Author: cijliu 3 | * @Date: 2021-02-02 15:48:13 4 | * @LastEditTime: 2021-02-24 17:26:52 5 | */ 6 | #include "include/h264.h" 7 | #include "sys/stat.h" 8 | #include 9 | #define RTP_TS_DEFAULT (3600) 10 | static uint8_t *h264_nal_data_ptr(uint8_t *ptr) 11 | { 12 | if(ptr[0] == 0x00 && ptr[1] == 0x00 && ptr[2] == 0x01) { 13 | return &ptr[3]; 14 | } 15 | if(ptr[0] == 0x00 && ptr[1] == 0x00 && ptr[2] == 0x00 && ptr[3] == 0x01) { 16 | return &ptr[4]; 17 | } 18 | return NULL; 19 | } 20 | static int h264_nal_is_header(uint8_t *ptr) 21 | { 22 | if(ptr[0] == 0x00 && ptr[1] == 0x00 && ptr[2] == 0x01){ 23 | return 0; 24 | } 25 | if(ptr[0] == 0x00 && ptr[1] == 0x00 && ptr[2] == 0x00 && ptr[3] == 0x01){ 26 | return 0; 27 | } 28 | return -1; 29 | } 30 | static uint8_t *h264_next_nal(uint8_t *ptr, uint8_t *end) 31 | { 32 | uint8_t *p = ptr; 33 | while(p < end){ 34 | if(!h264_nal_is_header(p)){ 35 | return p; 36 | } 37 | p++; 38 | } 39 | return NULL; 40 | } 41 | h264_nalu_t *h264_nal_packet_malloc(unsigned char *buf, int len) 42 | { 43 | uint8_t *end = buf + len - 1; 44 | uint8_t *data = h264_nal_data_ptr(buf); 45 | h264_nalu_t *nalu = (h264_nalu_t *)malloc(sizeof(h264_nalu_t)); 46 | h264_nalu_t *h264_nal = nalu; 47 | while(data && data < end){ 48 | memset(nalu, 0, sizeof(h264_nalu_t)); 49 | uint8_t *next = h264_next_nal(data, end); 50 | 51 | nalu->type = H264_NAL(data[0]); 52 | nalu->data = data; 53 | nalu->len = next - data; 54 | if(next == NULL) { 55 | nalu->len = end - data + 1; 56 | return h264_nal; 57 | } 58 | nalu->next = (h264_nalu_t *)malloc(sizeof(h264_nalu_t)); 59 | nalu = nalu->next; 60 | data = h264_nal_data_ptr(next); 61 | } 62 | free(h264_nal); 63 | return NULL; 64 | } 65 | 66 | void h264_nal_packet_free(h264_nalu_t *nal) 67 | { 68 | h264_nalu_t *p = nal; 69 | while(p){ 70 | h264_nalu_t *next = p->next; 71 | free(p); 72 | p = next; 73 | } 74 | nal = NULL; 75 | } 76 | static rtp_packet_t* rtp_packet_nalu(rtp_header_t *header, uint8_t *data, uint32_t len) 77 | { 78 | RTP_ASSERT(header); 79 | RTP_ASSERT(data); 80 | uint32_t payload_size = RTP_MAX_PAYLOAD - sizeof(rtp_header_t); 81 | if(len > payload_size) { 82 | return NULL; 83 | } 84 | rtp_packet_t *ptk = (rtp_packet_t*)malloc(sizeof(rtp_packet_t)); 85 | rtp_header_t *hdr = (rtp_header_t*)ptk->data; 86 | memset(ptk, 0, sizeof(rtp_packet_t)); 87 | memcpy(hdr, header, sizeof(rtp_header_t)); 88 | memcpy(ptk->data + sizeof(rtp_header_t), data, len); 89 | hdr->m = 1; 90 | hdr->seq = htons(hdr->seq); 91 | hdr->ts = htonl(hdr->ts); 92 | ptk->next = NULL; 93 | ptk->len = len + sizeof(rtp_header_t); 94 | header->seq++; 95 | header->ts += RTP_TS_DEFAULT; 96 | return ptk; 97 | } 98 | static rtp_packet_t* rtp_packet_nalu_with_fu_a(rtp_header_t *header, uint8_t nalu_type, uint8_t *data, uint32_t len) 99 | { 100 | RTP_ASSERT(header); 101 | RTP_ASSERT(data); 102 | uint32_t size = 0; 103 | uint32_t payload_size = RTP_MAX_PAYLOAD - sizeof(rtp_header_t) - 2; 104 | if(len < payload_size) { 105 | return NULL; 106 | } 107 | rtp_packet_t *ptk = (rtp_packet_t*)malloc(sizeof(rtp_packet_t)); 108 | rtp_packet_t *cur = ptk; 109 | memset(ptk, 0, sizeof(rtp_packet_t)); 110 | do{ 111 | memcpy(&cur->nalu.hdr, header, sizeof(rtp_header_t)); 112 | cur->nalu.hdr.seq = htons(cur->nalu.hdr.seq); 113 | cur->nalu.hdr.ts = htonl(cur->nalu.hdr.ts); 114 | cur->nalu.fu_indicator = (nalu_type & 0xe0) | 28; 115 | cur->nalu.fu_header = (nalu_type & 0x1f); //FU-A 116 | if(cur == ptk){ 117 | cur->nalu.fu_header |=0x80;//FU-A 118 | } 119 | memcpy(cur->nalu.rbsp, data + size, payload_size); 120 | size += payload_size; 121 | len -= payload_size; 122 | cur->len = RTP_MAX_PAYLOAD; 123 | rtp_packet_t *next = (rtp_packet_t*)malloc(sizeof(rtp_packet_t)); 124 | memset(next, 0, sizeof(rtp_packet_t)); 125 | cur->next = next; 126 | cur = next; 127 | header->seq++; 128 | } while(len > payload_size); 129 | 130 | memcpy(&cur->nalu.hdr, header, sizeof(rtp_header_t)); 131 | cur->nalu.hdr.m = 1; 132 | cur->nalu.hdr.seq = htons(cur->nalu.hdr.seq); 133 | cur->nalu.hdr.ts = htonl(cur->nalu.hdr.ts); 134 | cur->nalu.fu_indicator = (nalu_type & 0xe0) | 28; 135 | cur->nalu.fu_header = (nalu_type & 0x1f) | 0x40; //FU-A 136 | memcpy(cur->nalu.rbsp, data + size, len); 137 | cur->len = len + sizeof(rtp_header_t) + 2; 138 | header->seq++; 139 | header->ts += RTP_TS_DEFAULT; 140 | return ptk; 141 | } 142 | rtp_packet_t* rtp_h264_packet_malloc(rtp_header_t *header, uint8_t *data, uint32_t len) 143 | { 144 | uint32_t payload_size = RTP_MAX_PAYLOAD - sizeof(rtp_header_t); 145 | if(len > payload_size){ 146 | uint8_t nalu_type = data[0]; 147 | uint8_t *nalu_rbsp = &data[1]; 148 | uint32_t rbsp_len = len - 1; 149 | return rtp_packet_nalu_with_fu_a(header, nalu_type, nalu_rbsp, rbsp_len); 150 | } 151 | return rtp_packet_nalu(header, data, len); 152 | } -------------------------------------------------------------------------------- /src/rtp.c: -------------------------------------------------------------------------------- 1 | /* 2 | * @Author: cijliu 3 | * @Date: 2021-02-04 16:35:26 4 | * @LastEditTime: 2021-02-26 16:39:31 5 | */ 6 | #include "include/rtp.h" 7 | #include "include/h264.h" 8 | #define RTP_SSRC_DEFAULT (0xd160b58f) 9 | #define RTP_PAYLOAD_DEFAULT (RTP_H264) 10 | #define RTP_MALLOC_REGISTER(hdr) switch(hdr->pt){ 11 | #define RTP_REGISTER(pt, func) \ 12 | { \ 13 | case pt: \ 14 | return func(header, data, len); \ 15 | } 16 | 17 | #define RTP_MALLOC_REGISTER_END() } 18 | // void rtp_set_ssrc(rtp_header_t *header, uint32_t ssrc) 19 | // { 20 | // RTP_ASSERT(header); 21 | // header->ssrc = htonl(ssrc); 22 | // } 23 | 24 | // void rtp_set_pt(rtp_header_t *header, rtp_pt_enum_t e) 25 | // { 26 | // RTP_ASSERT(header); 27 | // header->pt = e; 28 | // } 29 | 30 | // void rtp_set_ts(rtp_header_t *header, uint32_t ts) 31 | // { 32 | // RTP_ASSERT(header); 33 | // header->ts = htonl(ts); 34 | // } 35 | 36 | // void rtp_set_seq(rtp_header_t *header, uint16_t seq) 37 | // { 38 | // RTP_ASSERT(header); 39 | // header->seq = htons(seq); 40 | // } 41 | 42 | void rtp_header_init(rtp_header_t *header) 43 | { 44 | RTP_ASSERT(header); 45 | memset(header, 0, sizeof(rtp_header_t)); 46 | header->v = 2; 47 | header->pt = RTP_PAYLOAD_DEFAULT; 48 | header->ssrc = htonl(RTP_SSRC_DEFAULT); 49 | } 50 | 51 | rtp_packet_t* rtp_packet_malloc(rtp_header_t *header, uint8_t *data, uint32_t len) 52 | { 53 | RTP_ASSERT(header); 54 | RTP_ASSERT(data); 55 | 56 | RTP_MALLOC_REGISTER(header) 57 | RTP_REGISTER(RTP_H264, rtp_h264_packet_malloc) 58 | RTP_MALLOC_REGISTER_END() 59 | 60 | } 61 | 62 | void rtp_packet_free(rtp_packet_t *pkt) 63 | { 64 | if(pkt == NULL) return; 65 | rtp_packet_t *p = pkt; 66 | while(p){ 67 | rtp_packet_t *next = p->next; 68 | free(p); 69 | p = next; 70 | } 71 | pkt == NULL; 72 | } 73 | -------------------------------------------------------------------------------- /src/rtsp_handler.c: -------------------------------------------------------------------------------- 1 | /* 2 | * @Author: cijliu 3 | * @Date: 2021-02-01 14:09:37 4 | * @LastEditTime: 2021-02-26 16:39:45 5 | */ 6 | #include "include/rtsp.h" 7 | #include "include/rtsp_parse.h" 8 | #include "include/rtsp_handler.h" 9 | #define EVENT_PARSE(msg) \ 10 | rtsp_msg_t _rtsp; \ 11 | rtsp_parse_msg(msg, &_rtsp); \ 12 | switch(_rtsp.request.method){ 13 | 14 | #define EVENT_END(func) \ 15 | default: \ 16 | func(_rtsp); \ 17 | break; \ 18 | } \ 19 | return _rtsp; 20 | 21 | 22 | #define EVENT(m,func,enable) \ 23 | { \ 24 | case m:{ \ 25 | if(enable)func(_rtsp); \ 26 | break; \ 27 | } \ 28 | } 29 | 30 | #define RELY_ADD_COND(m,v,msg, args...) \ 31 | do{ \ 32 | if(m == v){ \ 33 | char str[2048]={0}; \ 34 | sprintf(str, ##args); \ 35 | sprintf(msg, "%s%s", msg,str); \ 36 | } \ 37 | }while(0) 38 | 39 | #define RELY_ADD(msg, args...) RELY_ADD_COND(0,0,msg,##args) 40 | 41 | void event_error_handler(rtsp_msg_t rtsp) 42 | { 43 | printf("undefine rtsp type\n"); 44 | } 45 | void event_default_handler(rtsp_msg_t rtsp) 46 | { 47 | //printf("undefine rtsp type\n"); 48 | } 49 | rtsp_msg_t rtsp_msg_load(const char *msg) 50 | { 51 | EVENT_PARSE(msg) 52 | EVENT(OPTIONS, rtsp_options_handler,0); 53 | EVENT(DESCRIBE, rtsp_describe_handler,0); 54 | EVENT(SETUP, rtsp_setup_handler,0); 55 | EVENT(PLAY, rtsp_play_handler,0); 56 | EVENT(RECORD, rtsp_record_handler,0); 57 | EVENT(PAUSE, rtsp_pause_handler,0); 58 | EVENT(TEARDOWN, rtsp_teardown_handler,0); 59 | EVENT(ANNOUNCE, rtsp_announce_handler,0); 60 | EVENT(SET_PARAMETER, rtsp_set_parameter_handler,0); 61 | EVENT(GET_PARAMETER, rtsp_get_parameter_handler,0); 62 | EVENT(REDIRECT, rtsp_redirect_handler,0); 63 | EVENT_END(event_error_handler); 64 | } 65 | 66 | int rtsp_rely_dumps(rtsp_rely_t rely, char *msg, uint32_t len) 67 | { 68 | rtsp_method_enum_t method = rely.request.method; 69 | if(len < 1024) return -1; 70 | memset(msg, 0, len); 71 | RELY_ADD(msg, "RTSP/1.0 %d %s\r\n", rely.status, rely.desc); 72 | RELY_ADD(msg, "CSeq: %d\r\n", rely.cseq); 73 | RELY_ADD(msg, "Date: %s\r\n",rely.datetime); 74 | RELY_ADD_COND(method, OPTIONS, msg, "Public: %s\r\n", DEFAULT_RTSP_SUPPORT_METHOD); 75 | RELY_ADD_COND(method, DESCRIBE, msg, "Content-type: application/sdp\r\n"); 76 | RELY_ADD_COND(((method == SETUP)|(method == PLAY)|(method == TEARDOWN)),1, msg, 77 | "Session: %s;timeout=%d\r\n", rely.session, rely.timeout == 0?60:rely.timeout); 78 | RELY_ADD_COND(method, SETUP, msg, "Transport: RTP/AVP%s;%scast;client_port=%d-%d;server_port=%d-%d\r\n", 79 | rely.tansport.is_tcp ? "/TCP" : "", 80 | rely.tansport.is_multicast ? "multi" : "uni", 81 | rely.tansport.client_port, 82 | rely.tansport.client_port + 1, 83 | rely.tansport.server_port, 84 | rely.tansport.server_port + 1); 85 | RELY_ADD_COND(method, PLAY, msg, "Range: npt=0.000-\r\n"); 86 | RELY_ADD_COND(method, PLAY, msg, "RTP-Info: url=rtsp://%s:%d/%s;seq=%d;rtptime=%ld\r\n", 87 | rely.request.url.ip, 88 | rely.request.url.port, 89 | rely.request.url.uri, 90 | rely.rtp_seq, 91 | rely.rtptime); 92 | RELY_ADD(msg, "Content-Length: %d\r\n\r\n", rely.sdp_len); 93 | RELY_ADD_COND(method, DESCRIBE, msg, "%s", rely.sdp); 94 | //printf("msg:%ld\n%s\n",strlen(msg),msg); 95 | return 0; 96 | 97 | } 98 | rtsp_rely_t get_rely(rtsp_msg_t rtsp) 99 | { 100 | rtsp_rely_t rely; 101 | memset(&rely, 0, sizeof(rtsp_rely_t)); 102 | sprintf(rely.desc,"OK"); 103 | sprintf(rely.session,"%p",&rtsp); 104 | rely.request = rtsp.request; 105 | rely.status = 200; 106 | rely.cseq = rtsp.cseq; 107 | rely.sdp_len = 0; 108 | memcpy(rely.session,rtsp.session, strlen(rtsp.session)); 109 | rely.tansport = rtsp.tansport; 110 | return rely; 111 | } 112 | -------------------------------------------------------------------------------- /src/rtsp_parse.c: -------------------------------------------------------------------------------- 1 | /* 2 | * @Author: cijliu 3 | * @Date: 2021-02-04 16:42:54 4 | * @LastEditTime: 2021-02-26 16:40:06 5 | */ 6 | 7 | #include "include/rtsp.h" 8 | #define RTSP_METHOD_PARSE(msg, val) do{ if(strcmp(opt, #val) == 0) return val; }while(0) 9 | #define FUNC_CHECK(func, num) do{ if(num != func) return -1; }while(0) 10 | 11 | #define RTSP_LINE(msg, key, line) \ 12 | do{ \ 13 | char *str = strstr(msg, key); \ 14 | if(str == NULL){ \ 15 | return -1; \ 16 | } \ 17 | FUNC_CHECK(sscanf(str,"%[^\n]",line),1); \ 18 | }while(0) 19 | 20 | #define RTSP_PARSE(msg, key,num,args...) \ 21 | do{ \ 22 | char line[DEFAULT_STRING_MAX_LEN]; \ 23 | RTSP_LINE(msg, key,line); \ 24 | FUNC_CHECK(sscanf(line, ##args),num); \ 25 | }while(0) 26 | 27 | 28 | static const char *method[] = { 29 | "OPTIONS", 30 | "DESCRIBE", 31 | "SETUP", 32 | "PLAY", 33 | "RECORD", 34 | "PAUSE", 35 | "TEARDOWN", 36 | "ANNOUNCE", 37 | "SET_PARAMETER", 38 | "GET_PARAMETER", 39 | "REDIRECT", 40 | "BUTT", 41 | }; 42 | 43 | 44 | static rtsp_method_enum_t rtsp_parse_method(const char *opt) 45 | { 46 | RTSP_METHOD_PARSE(opt, OPTIONS); 47 | RTSP_METHOD_PARSE(opt, DESCRIBE); 48 | RTSP_METHOD_PARSE(opt, SETUP); 49 | RTSP_METHOD_PARSE(opt, PLAY); 50 | RTSP_METHOD_PARSE(opt, RECORD); 51 | RTSP_METHOD_PARSE(opt, PAUSE); 52 | RTSP_METHOD_PARSE(opt, TEARDOWN); 53 | RTSP_METHOD_PARSE(opt, ANNOUNCE); 54 | RTSP_METHOD_PARSE(opt, SET_PARAMETER); 55 | RTSP_METHOD_PARSE(opt, GET_PARAMETER); 56 | RTSP_METHOD_PARSE(opt, REDIRECT); 57 | return BUTT; 58 | } 59 | 60 | 61 | 62 | static int rtsp_parse_session(const char *msg, char *session) 63 | { 64 | RTSP_PARSE(msg, "Session",1, "Session: %s\r\n", session); 65 | return 0; 66 | } 67 | 68 | 69 | static int rtsp_parse_cseq(const char *msg, int *cseq) 70 | { 71 | RTSP_PARSE(msg, "CSeq",1, "CSeq: %d\r\n", cseq); 72 | return 0; 73 | } 74 | 75 | static int rtsp_parse_transport(const char *msg, rtsp_transport_t *trans) 76 | { 77 | char tcpip[DEFAULT_STRING_MIN_LEN]; 78 | char cast[DEFAULT_STRING_MIN_LEN]; 79 | RTSP_PARSE(msg, "Transport", 4, "Transport: %[^;];%[^;];client_port=%d-%d\r\n", tcpip, cast, &trans->rtp_port, &trans->rtcp_port); 80 | trans->is_tcp = strcmp(tcpip, "RTP/AVP/TCP") == 0 ? 1:0; 81 | trans->is_multicast = strcmp(cast, "multicast") == 0 ? 1:0; 82 | 83 | return 0; 84 | 85 | } 86 | 87 | static int rtsp_parse_request(const char *msg, rtsp_request_t *req) 88 | { 89 | char line[DEFAULT_STRING_MAX_LEN]; 90 | char method[DEFAULT_STRING_MIN_LEN]; 91 | char addr[DEFAULT_STRING_MIN_LEN]; 92 | int port = 0; 93 | FUNC_CHECK(sscanf(msg,"%[^\n]",line), 1); 94 | FUNC_CHECK(sscanf(line, "%s %[^'/']//%[^'/']/%s RTSP/1.0\r\n", method, req->url.prefix, addr, req->url.uri), 4); 95 | FUNC_CHECK(sscanf(addr, "%[^':']:%d",req->url.ip,&port), 2); 96 | req->url.port = port == 0 ? DEFAULT_RTSP_PORT:port; 97 | req->method = rtsp_parse_method(method); 98 | return 0; 99 | 100 | } 101 | 102 | int rtsp_parse_msg(const char *msg, rtsp_msg_t *rtsp) 103 | { 104 | memset(rtsp, 0, sizeof(rtsp_msg_t)); 105 | FUNC_CHECK(rtsp_parse_request(msg, &rtsp->request), 0); 106 | FUNC_CHECK(rtsp_parse_cseq(msg, &rtsp->cseq), 0); 107 | 108 | if(rtsp->request.method == SETUP){ 109 | FUNC_CHECK(rtsp_parse_transport(msg, &rtsp->tansport), 0); 110 | } 111 | if(rtsp->request.method == PLAY){ 112 | FUNC_CHECK(rtsp_parse_session(msg, rtsp->session), 0); 113 | } 114 | 115 | 116 | 117 | } 118 | -------------------------------------------------------------------------------- /src/tcp.c: -------------------------------------------------------------------------------- 1 | /* 2 | * @Author: cijliu 3 | * @Date: 2021-02-11 14:17:59 4 | * @LastEditTime: 2021-02-23 18:01:54 5 | */ 6 | #include "include/net.h" 7 | int tcp_server_init(tcp_t *tcp, int port) 8 | { 9 | memset(tcp, 0, sizeof(tcp_t)); 10 | tcp->sock = socket(AF_INET, SOCK_STREAM, 0); 11 | if (tcp->sock == -1) { 12 | printf("create socket failed : %d\n", errno); 13 | return -1; 14 | } 15 | memset(&tcp->addr, 0, sizeof(struct sockaddr_in)); 16 | tcp->addr.sin_family = AF_INET; 17 | tcp->addr.sin_addr.s_addr = htonl(INADDR_ANY); 18 | tcp->addr.sin_port = htons(port); 19 | 20 | int opt = 1; 21 | setsockopt(tcp->sock,SOL_SOCKET,SO_REUSEADDR,&opt,sizeof(opt)); 22 | int ret = bind(tcp->sock, (struct sockaddr*)&tcp->addr, sizeof(struct sockaddr_in)); 23 | if (ret) { 24 | printf("bind socket to address failed : %d\n", errno); 25 | close(tcp->sock); 26 | return -1; 27 | } 28 | ret = listen(tcp->sock, TCP_MAX_CLIENT); //XXX 29 | if (ret) { 30 | printf("listen socket failed : %d\n", errno); 31 | close(tcp->sock); 32 | return -1; 33 | } 34 | tcp->port = port; 35 | return 0; 36 | } 37 | 38 | int tcp_server_wait_client(tcp_t *tcp) 39 | { 40 | int i = 0; 41 | socklen_t addrlen = sizeof(tcp->addr); 42 | while(tcp->client[i] != 0 && i < TCP_MAX_CLIENT)i++; 43 | tcp->client[i] = accept(tcp->sock, (struct sockaddr*)&tcp->addr, &addrlen); 44 | return tcp->client[i]; 45 | 46 | } 47 | 48 | int tcp_server_close_client(tcp_t *tcp, int client) 49 | { 50 | int i; 51 | while(tcp->client[i] != client && i < TCP_MAX_CLIENT) i++; 52 | close(tcp->client[i]); 53 | tcp->client[i] = 0; 54 | return 0; 55 | } 56 | 57 | int tcp_server_send_msg(tcp_t *tcp, int client, unsigned char *data, int len) 58 | { 59 | int i = 0; 60 | while(tcp->client[i] != client && i < TCP_MAX_CLIENT) i++; 61 | if(i >= TCP_MAX_CLIENT) { 62 | return -1; 63 | } 64 | return send(client, data, len, 0); 65 | } 66 | 67 | int tcp_server_receive_msg(tcp_t *tcp, int client, unsigned char *data, int len) 68 | { 69 | int i = 0; 70 | while(tcp->client[i] != client && i < TCP_MAX_CLIENT) i++; 71 | if(i >= TCP_MAX_CLIENT) { 72 | return -1; 73 | } 74 | return read(client, data, len); 75 | } 76 | 77 | int tcp_server_deinit(tcp_t *tcp) 78 | { 79 | int i; 80 | for(i=0; i < TCP_MAX_CLIENT; i++){ 81 | if(tcp->client[i] != 0){ 82 | close(tcp->client[i]); 83 | tcp->client[i] = 0; 84 | } 85 | } 86 | close(tcp->sock); 87 | return 0; 88 | } 89 | 90 | -------------------------------------------------------------------------------- /src/udp.c: -------------------------------------------------------------------------------- 1 | /* 2 | * @Author: cijliu 3 | * @Date: 2021-02-11 21:20:26 4 | * @LastEditTime: 2021-02-26 09:29:41 5 | */ 6 | 7 | #include "include/net.h" 8 | int udp_server_init(udp_t *udp, int port) 9 | { 10 | int size = 50 *1024; 11 | memset(udp, 0, sizeof(udp_t)); 12 | udp->sock = socket(AF_INET, SOCK_DGRAM, 0); 13 | if (udp->sock == -1) { 14 | printf("create socket failed : %d\n", errno); 15 | return -1; 16 | } 17 | //setsockopt(udp->sock, SOL_SOCKET, SO_SNDBUF, (char *)&size, sizeof(size)); 18 | memset(&udp->addr, 0, sizeof(struct sockaddr_in)); 19 | udp->addr.sin_family = AF_INET; 20 | udp->addr.sin_addr.s_addr = htonl(INADDR_ANY); 21 | udp->addr.sin_port = htons(port); 22 | 23 | 24 | int ret = bind(udp->sock, (struct sockaddr*)&udp->addr, sizeof(struct sockaddr_in)); 25 | if (ret) { 26 | printf("bind socket to address failed : %d\n", errno); 27 | close(udp->sock); 28 | return -1; 29 | } 30 | ret = fcntl(udp->sock, F_GETFL, 0); 31 | if (ret < 0) { 32 | printf("fcntl F_GETFL failed: %d\n", errno); 33 | } else { 34 | ret |= O_NONBLOCK; 35 | ret = fcntl(udp->sock, F_SETFL, ret); 36 | if (ret < 0) { 37 | printf("fcntl F_SETFL failed: %d\n", errno); 38 | } 39 | } 40 | udp->port = port; 41 | return 0; 42 | } 43 | int udp_server_send_msg(udp_t *udp, const char *ip, const int port, unsigned char *data, int len) 44 | { 45 | struct sockaddr_in addr; 46 | memset(&addr, 0, sizeof(addr)); 47 | addr.sin_family = AF_INET; 48 | addr.sin_addr.s_addr = inet_addr(ip); 49 | addr.sin_port = htons(port); 50 | int ret; 51 | int try = 3; 52 | do{ 53 | ret = sendto(udp->sock, (const unsigned char*)data, len, 0, (struct sockaddr*)&addr, sizeof(addr)); 54 | if (ret != len) { 55 | printf("udp %d\n",ret); 56 | //return ret; 57 | } 58 | else { 59 | return 0; 60 | } 61 | try--; 62 | } while(ret != len && try > 0); 63 | 64 | return -1; 65 | } 66 | 67 | int udp_server_recive_msg(udp_t *udp, ip_t *ip, unsigned char *data, int len) 68 | { 69 | struct sockaddr_in addr; 70 | int size = 0; 71 | int ret = recvfrom(udp->sock, data, len, 0, (struct sockaddr *)&addr, &size); 72 | if(ret) 73 | { 74 | return -1; 75 | } 76 | sprintf(ip->ip, "%s", inet_ntoa(addr.sin_addr)); 77 | ip->port = ntohs(addr.sin_port); 78 | return size; 79 | } 80 | 81 | int udp_server_deinit(udp_t *udp) 82 | { 83 | close(udp->sock); 84 | return 0; 85 | } 86 | --------------------------------------------------------------------------------