Changeset 1569 in ntrip for trunk/ntripclient
- Timestamp:
- Feb 10, 2009, 1:18:23 PM (16 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/ntripclient/ntripclient.c
r1183 r1569 1 1 /* 2 2 NTRIP client for POSIX. 3 $Id: ntripclient.c,v 1.4 5 2008/05/15 16:51:04stoecker Exp $3 $Id: ntripclient.c,v 1.46 2008/11/04 15:35:03 stoecker Exp $ 4 4 Copyright (C) 2003-2008 by Dirk Stöcker <soft@dstoecker.de> 5 5 … … 35 35 typedef u_long in_addr_t; 36 36 typedef size_t socklen_t; 37 void myperror(char *s) 38 { 39 fprintf(stderr, "%s: %d\n", s, WSAGetLastError()); 40 } 37 41 #else 38 42 typedef int sockettype; … … 47 51 #define closesocket(sock) close(sock) 48 52 #define ALARMTIME (2*60) 53 #define myperror perror 49 54 #endif 50 55 … … 55 60 /* The string, which is send as agent in HTTP request */ 56 61 #define AGENTSTRING "NTRIP NtripClientPOSIX" 62 #define TIME_RESOLUTION 125 57 63 58 64 #define MAXDATASIZE 1000 /* max number of bytes we can get at once */ 59 65 60 66 /* CVS revision and version */ 61 static char revisionstr[] = "$Revision: 1.4 5$";62 static char datestr[] = "$Date: 2008/ 05/15 16:51:04$";63 64 enum MODE { HTTP = 1, RTSP = 2, NTRIP1 = 3, AUTO = 4, END };67 static char revisionstr[] = "$Revision: 1.46 $"; 68 static char datestr[] = "$Date: 2008/11/04 15:35:03 $"; 69 70 enum MODE { HTTP = 1, RTSP = 2, NTRIP1 = 3, AUTO = 4, UDP = 5, END }; 65 71 66 72 struct Args … … 434 440 else if(!strcmp(optarg,"r") || !strcmp(optarg,"rtsp")) 435 441 args->mode = RTSP; 442 else if(!strcmp(optarg,"u") || !strcmp(optarg,"udp")) 443 args->mode = UDP; 436 444 else if(!strcmp(optarg,"a") || !strcmp(optarg,"auto")) 437 445 args->mode = AUTO; … … 485 493 " 3, n, ntrip1 NTRIP Version 1.0 Caster\n" 486 494 " 4, a, auto automatic detection (default)\n" 495 " 5, u, udp NTRIP Version 2.0 Caster in UDP mode\n" 487 496 "or using an URL:\n%s ntrip:mountpoint[/user[:password]][@[server][:port][@proxyhost[:proxyport]]][;nmea]\n" 488 497 "\nExpert options:\n" … … 680 689 error = 1; 681 690 } 682 else if((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1) 691 else if((sockfd = socket(AF_INET, (args.mode == UDP ? SOCK_DGRAM : 692 SOCK_STREAM), 0)) == -1) 683 693 { 684 perror("socket");694 myperror("socket"); 685 695 error = 1; 686 696 } … … 694 704 if(!stop && !error) 695 705 { 696 if(args.data && *args.data != '%' && args.mode == RTSP) 706 if(args.mode == UDP) 707 { 708 int session, tim, seq, init; 709 char rtpbuf[1526]; 710 int i=12, j; 711 712 init = time(0); 713 srand(init); 714 session = rand(); 715 tim = rand(); 716 seq = rand(); 717 718 rtpbuf[0] = (2<<6); 719 /* padding, extension, csrc are empty */ 720 rtpbuf[1] = 97; 721 /* marker is empty */ 722 rtpbuf[2] = (seq>>8)&0xFF; 723 rtpbuf[3] = (seq)&0xFF; 724 rtpbuf[4] = (tim>>24)&0xFF; 725 rtpbuf[5] = (tim>>16)&0xFF; 726 rtpbuf[6] = (tim>>8)&0xFF; 727 rtpbuf[7] = (tim)&0xFF; 728 /* sequence and timestamp are empty */ 729 rtpbuf[8] = (session>>24)&0xFF; 730 rtpbuf[9] = (session>>16)&0xFF; 731 rtpbuf[10] = (session>>8)&0xFF; 732 rtpbuf[11] = (session)&0xFF; 733 ++seq; 734 735 j = snprintf(rtpbuf+i, sizeof(rtpbuf)-i-40, /* leave some space for login */ 736 "GET /%s HTTP/1.1\r\n" 737 "Host: %s\r\n" 738 "Ntrip-Version: Ntrip/2.0\r\n" 739 "User-Agent: %s/%s\r\n" 740 "%s%s%s" 741 "Connection: close%s", 742 args.data ? args.data : "", args.server, AGENTSTRING, revisionstr, 743 args.nmea ? "Ntrip-GGA: " : "", args.nmea ? args.nmea : "", 744 args.nmea ? "\r\n" : "", 745 (*args.user || *args.password) ? "\r\nAuthorization: Basic " : ""); 746 i += j; 747 if(i > (int)sizeof(rtpbuf)-40 || j < 0) /* second check for old glibc */ 748 { 749 fprintf(stderr, "Requested data too long\n"); 750 stop = 1; 751 } 752 else 753 { 754 i += encode(rtpbuf+i, sizeof(rtpbuf)-i-4, args.user, args.password); 755 if(i > (int)sizeof(rtpbuf)-4) 756 { 757 fprintf(stderr, "Username and/or password too long\n"); 758 stop = 1; 759 } 760 else 761 { 762 struct sockaddr_in local; 763 socklen_t len; 764 765 rtpbuf[i++] = '\r'; 766 rtpbuf[i++] = '\n'; 767 rtpbuf[i++] = '\r'; 768 rtpbuf[i++] = '\n'; 769 770 771 /* fill structure with local address information for UDP */ 772 memset(&local, 0, sizeof(local)); 773 local.sin_family = AF_INET; 774 local.sin_port = htons(args.udpport); 775 local.sin_addr.s_addr = htonl(INADDR_ANY); 776 len = sizeof(local); 777 778 /* bind() in order to get a random RTP client_port */ 779 if((bind(sockfd, (struct sockaddr *)&local, len)) < 0) 780 { 781 myperror("bind"); 782 error = 1; 783 } 784 else if(connect(sockfd, (struct sockaddr *)&their_addr, 785 sizeof(struct sockaddr)) == -1) 786 { 787 myperror("connect"); 788 error = 1; 789 } 790 else if(send(sockfd, rtpbuf, i, 0) != i) 791 { 792 myperror("Could not send UDP packet"); 793 stop = 1; 794 } 795 else 796 { 797 if((numbytes=recv(sockfd, rtpbuf, sizeof(rtpbuf)-1, 0)) > 0) 798 { 799 int sn = 0x10000, ts=0; 800 /* we don't expect message longer than 1513, so we cut the last 801 byte for security reasons to prevent buffer overrun */ 802 rtpbuf[numbytes] = 0; 803 if(numbytes > 17+12 && 804 (!strncmp(rtpbuf+12, "HTTP/1.1 200 OK\r\n", 17) || 805 !strncmp(rtpbuf+12, "HTTP/1.0 200 OK\r\n", 17))) 806 { 807 const char *sessioncheck = "session: "; 808 const char *datacheck = "Content-Type: gnss/data\r\n"; 809 int l = strlen(datacheck)-1; 810 int j=0; 811 for(i = 12; j != l && i < numbytes-l; ++i) 812 { 813 for(j = 0; j < l && rtpbuf[i+j] == datacheck[j]; ++j) 814 ; 815 } 816 if(i == numbytes-l) 817 { 818 fprintf(stderr, "No 'Content-Type: gnss/data' found\n"); 819 error = 1; 820 } 821 /* check for Session */ 822 l = strlen(sessioncheck)-1; 823 j=0; 824 for(i = 12; j != l && i < numbytes-l; ++i) 825 { 826 for(j = 0; j < l && tolower(rtpbuf[i+j]) == sessioncheck[j]; ++j) 827 ; 828 } 829 if(i != numbytes-l) /* found a session number */ 830 { 831 i+=l; 832 session = 0; 833 while(i < numbytes && rtpbuf[i] >= '0' && rtpbuf[i] <= '9') 834 session = session * 10 + rtpbuf[i++]-'0'; 835 if(rtpbuf[i] != '\r') 836 { 837 fprintf(stderr, "Could not extract session number\n"); 838 stop = 1; 839 } 840 } 841 } 842 else 843 { 844 int k; 845 fprintf(stderr, "Could not get the requested data: "); 846 for(k = 12; k < numbytes && rtpbuf[k] != '\n' && rtpbuf[k] != '\r'; ++k) 847 { 848 fprintf(stderr, "%c", isprint(rtpbuf[k]) ? rtpbuf[k] : '.'); 849 } 850 fprintf(stderr, "\n"); 851 error = 1; 852 } 853 while(!stop && !error) 854 { 855 struct timeval tv = {1,0}; 856 fd_set fdr; 857 fd_set fde; 858 859 FD_ZERO(&fdr); 860 FD_ZERO(&fde); 861 FD_SET(sockfd, &fdr); 862 FD_SET(sockfd, &fde); 863 if(select(sockfd+1,&fdr,0,&fde,&tv) < 0) 864 { 865 fprintf(stderr, "Select problem.\n"); 866 error = 1; 867 continue; 868 } 869 i = recv(sockfd, rtpbuf, sizeof(rtpbuf), 0); 870 #ifndef WINDOWSVERSION 871 alarm(ALARMTIME); 872 #endif 873 if(i >= 12+1 && (unsigned char)rtpbuf[0] == (2 << 6) 874 && rtpbuf[1] >= 96 && rtpbuf[1] <= 98) 875 { 876 time_t ct; 877 int u,v,w; 878 u = ((unsigned char)rtpbuf[2]<<8)+(unsigned char)rtpbuf[3]; 879 v = ((unsigned char)rtpbuf[4]<<24)+((unsigned char)rtpbuf[5]<<16) 880 +((unsigned char)rtpbuf[6]<<8)+(unsigned char)rtpbuf[7]; 881 w = ((unsigned char)rtpbuf[8]<<24)+((unsigned char)rtpbuf[9]<<16) 882 +((unsigned char)rtpbuf[10]<<8)+(unsigned char)rtpbuf[11]; 883 884 if(sn == 0x10000) {sn = u-1;ts=v-1;} 885 else if(u < -30000 && sn > 30000) sn -= 0xFFFF; 886 if(session != w || ts > v) 887 { 888 fprintf(stderr, "Illegal UDP data received.\n"); 889 continue; 890 } 891 else if(u > sn) /* don't show out-of-order packets */ 892 { 893 if(rtpbuf[1] == 98) 894 { 895 fprintf(stderr, "Connection closed.\n"); 896 error = 1; 897 continue; 898 } 899 else if(rtpbuf[1] == 96) 900 { 901 fwrite(rtpbuf+12, (size_t)i-12, 1, stdout); 902 } 903 } 904 sn = u; ts = v; 905 906 /* Keep Alive */ 907 ct = time(0); 908 if(ct-init > 15) 909 { 910 tim += (ct-init)*1000000/TIME_RESOLUTION; 911 rtpbuf[0] = (2<<6); 912 /* padding, extension, csrc are empty */ 913 rtpbuf[1] = 96; 914 /* marker is empty */ 915 rtpbuf[2] = (seq>>8)&0xFF; 916 rtpbuf[3] = (seq)&0xFF; 917 rtpbuf[4] = (tim>>24)&0xFF; 918 rtpbuf[5] = (tim>>16)&0xFF; 919 rtpbuf[6] = (tim>>8)&0xFF; 920 rtpbuf[7] = (tim)&0xFF; 921 /* sequence and timestamp are empty */ 922 rtpbuf[8] = (session>>24)&0xFF; 923 rtpbuf[9] = (session>>16)&0xFF; 924 rtpbuf[10] = (session>>8)&0xFF; 925 rtpbuf[11] = (session)&0xFF; 926 ++seq; 927 init = ct; 928 929 if(send(sockfd, rtpbuf, 12, 0) != 12) 930 { 931 myperror("send"); 932 error = 1; 933 } 934 } 935 } 936 else if(i >= 0) 937 { 938 fprintf(stderr, "Illegal UDP header.\n"); 939 continue; 940 } 941 } 942 } 943 /* send connection close always to allow nice session closing */ 944 tim += (time(0)-init)*1000000/TIME_RESOLUTION; 945 rtpbuf[0] = (2<<6); 946 /* padding, extension, csrc are empty */ 947 rtpbuf[1] = 98; 948 /* marker is empty */ 949 rtpbuf[2] = (seq>>8)&0xFF; 950 rtpbuf[3] = (seq)&0xFF; 951 rtpbuf[4] = (tim>>24)&0xFF; 952 rtpbuf[5] = (tim>>16)&0xFF; 953 rtpbuf[6] = (tim>>8)&0xFF; 954 rtpbuf[7] = (tim)&0xFF; 955 /* sequence and timestamp are empty */ 956 rtpbuf[8] = (session>>24)&0xFF; 957 rtpbuf[9] = (session>>16)&0xFF; 958 rtpbuf[10] = (session>>8)&0xFF; 959 rtpbuf[11] = (session)&0xFF; 960 961 send(sockfd, rtpbuf, 12, 0); /* cleanup */ 962 } 963 } 964 } 965 } 966 else if(args.data && *args.data != '%' && args.mode == RTSP) 697 967 { 698 968 struct sockaddr_in local; … … 704 974 if((sockudp = socket(AF_INET, SOCK_DGRAM, 0)) == -1) 705 975 { 706 perror("socket");976 myperror("socket"); 707 977 error = 1; 708 978 } … … 718 988 if((bind(sockudp, (struct sockaddr *)&local, len)) < 0) 719 989 { 720 perror("bind");990 myperror("bind"); 721 991 error = 1; 722 992 } 723 993 else if((getsockname(sockudp, (struct sockaddr*)&local, &len)) == -1) 724 994 { 725 perror("local access failed");995 myperror("local access failed"); 726 996 error = 1; 727 997 } … … 729 999 sizeof(struct sockaddr)) == -1) 730 1000 { 731 perror("connect");1001 myperror("connect"); 732 1002 error = 1; 733 1003 } … … 742 1012 "Ntrip-Component: Ntripclient\r\n" 743 1013 "User-Agent: %s/%s\r\n" 744 "Transport: RTP/GNSS;unicast;client_port=%u\r\n" 745 "Authorization: Basic ", 1014 "Transport: RTP/GNSS;unicast;client_port=%u%s", 746 1015 args.server, proxyserver ? ":" : "", proxyserver ? args.port : "", 747 args.data, cseq++, AGENTSTRING, revisionstr, localport); 1016 args.data, cseq++, AGENTSTRING, revisionstr, localport, 1017 (*args.user || *args.password) ? "\r\nAuthorization: Basic " : ""); 748 1018 if(i > MAXDATASIZE-40 || i < 0) /* second check for old glibc */ 749 1019 { … … 777 1047 if(send(sockfd, buf, (size_t)i, 0) != i) 778 1048 { 779 perror("send");1049 myperror("send"); 780 1050 error = 1; 781 1051 } 782 1052 else if((numbytes=recv(sockfd, buf, MAXDATASIZE-1, 0)) == -1) 783 1053 { 784 perror("recv");1054 myperror("recv"); 785 1055 error = 1; 786 1056 } … … 868 1138 if((i = sendto(sockudp, rtpbuffer, 12, 0, 869 1139 (struct sockaddr *) &casterRTP, sizeof(casterRTP))) != 12) 870 perror("WARNING: could not send initial UDP packet");1140 myperror("WARNING: could not send initial UDP packet"); 871 1141 } 872 1142 if(!stop && !error) … … 887 1157 else if(send(sockfd, buf, (size_t)i, 0) != i) 888 1158 { 889 perror("send");1159 myperror("send"); 890 1160 error = 1; 891 1161 } … … 919 1189 while(!stop && !error) 920 1190 { 1191 char rtpbuffer[1526]; 921 1192 struct timeval tv = {1,0}; 922 1193 fd_set fdr; … … 937 1208 continue; 938 1209 } 939 i = recvfrom(sockudp, buf, 1526, 0,1210 i = recvfrom(sockudp, rtpbuffer, sizeof(rtpbuffer), 0, 940 1211 (struct sockaddr*) &addrRTP, &len); 941 1212 #ifndef WINDOWSVERSION 942 1213 alarm(ALARMTIME); 943 1214 #endif 944 if(i >= 12+1 && (unsigned char) buf[0] == (2 << 6) && buf[1] == 0x60)1215 if(i >= 12+1 && (unsigned char)rtpbuffer[0] == (2 << 6) && rtpbuffer[1] == 0x60) 945 1216 { 946 1217 int u,v,w; 947 u = ((unsigned char) buf[2]<<8)+(unsigned char)buf[3];948 v = ((unsigned char) buf[4]<<24)+((unsigned char)buf[5]<<16)949 +((unsigned char) buf[6]<<8)+(unsigned char)buf[7];950 w = ((unsigned char) buf[8]<<24)+((unsigned char)buf[9]<<16)951 +((unsigned char) buf[10]<<8)+(unsigned char)buf[11];1218 u = ((unsigned char)rtpbuffer[2]<<8)+(unsigned char)rtpbuffer[3]; 1219 v = ((unsigned char)rtpbuffer[4]<<24)+((unsigned char)rtpbuffer[5]<<16) 1220 +((unsigned char)rtpbuffer[6]<<8)+(unsigned char)rtpbuffer[7]; 1221 w = ((unsigned char)rtpbuffer[8]<<24)+((unsigned char)rtpbuffer[9]<<16) 1222 +((unsigned char)rtpbuffer[10]<<8)+(unsigned char)rtpbuffer[11]; 952 1223 953 1224 if(init) … … 961 1232 } 962 1233 else if(u > sn) /* don't show out-of-order packets */ 963 fwrite( buf+12, (size_t)i-12, 1, stdout);1234 fwrite(rtpbuffer+12, (size_t)i-12, 1, stdout); 964 1235 ct = time(0); 965 1236 if(ct-init > 15) … … 979 1250 else if(send(sockfd, buf, (size_t)i, 0) != i) 980 1251 { 981 perror("send");1252 myperror("send"); 982 1253 error = 1; 983 1254 } … … 1031 1302 else if(send(sockfd, buf, (size_t)i, 0) != i) 1032 1303 { 1033 perror("send");1304 myperror("send"); 1034 1305 error = 1; 1035 1306 } … … 1056 1327 sizeof(struct sockaddr)) == -1) 1057 1328 { 1058 perror("connect");1329 myperror("connect"); 1059 1330 error = 1; 1060 1331 } … … 1064 1335 { 1065 1336 i = snprintf(buf, MAXDATASIZE, 1066 "GET %s%s%s%s/ HTTP/1. 0\r\n"1337 "GET %s%s%s%s/ HTTP/1.1\r\n" 1067 1338 "Host: %s\r\n%s" 1068 1339 "User-Agent: %s/%s\r\n" … … 1077 1348 { 1078 1349 i=snprintf(buf, MAXDATASIZE-40, /* leave some space for login */ 1079 "GET %s%s%s%s/%s HTTP/1. 0\r\n"1350 "GET %s%s%s%s/%s HTTP/1.1\r\n" 1080 1351 "Host: %s\r\n%s" 1081 1352 "User-Agent: %s/%s\r\n" 1082 "Connection: close\r\n" 1083 "Authorization: Basic " 1353 "Connection: close%s" 1084 1354 , proxyserver ? "http://" : "", proxyserver ? proxyserver : "", 1085 1355 proxyserver ? ":" : "", proxyserver ? proxyport : "", 1086 1356 args.data, args.server, 1087 1357 args.mode == NTRIP1 ? "" : "Ntrip-Version: Ntrip/2.0\r\n", 1088 AGENTSTRING, revisionstr); 1358 AGENTSTRING, revisionstr, 1359 (*args.user || *args.password) ? "\r\nAuthorization: Basic " : ""); 1089 1360 if(i > MAXDATASIZE-40 || i < 0) /* second check for old glibc */ 1090 1361 { … … 1125 1396 if(send(sockfd, buf, (size_t)i, 0) != i) 1126 1397 { 1127 perror("send");1398 myperror("send"); 1128 1399 error = 1; 1129 1400 }
Note:
See TracChangeset
for help on using the changeset viewer.